未验证 提交 0ef56df4 编写于 作者: A Ankit Jain 提交者: GitHub

[wasm] Update Wasm.Build.Tests to build with net6.0 (#54936)

Co-authored-by: NLarry Ewing <lewing@microsoft.com>
上级 2be4fdc8
<Project> <Project>
<PropertyGroup> <PropertyGroup Condition="'$(RunScriptInputName)' == ''">
<RunScriptInputName Condition="'$(TargetOS)' == 'windows'">RunnerTemplate.cmd</RunScriptInputName> <RunScriptInputName Condition="'$(TargetOS)' == 'windows'">RunnerTemplate.cmd</RunScriptInputName>
<RunScriptInputName Condition="'$(TargetOS)' != 'windows'">RunnerTemplate.sh</RunScriptInputName> <RunScriptInputName Condition="'$(TargetOS)' != 'windows'">RunnerTemplate.sh</RunScriptInputName>
<RunScriptInputName Condition="'$(TargetOS)' == 'MacCatalyst' or '$(TargetOS)' == 'iOS' or '$(TargetOS)' == 'iOSSimulator' or '$(TargetOS)' == 'tvOS' or '$(TargetOS)' == 'tvOSSimulator'">AppleRunnerTemplate.sh</RunScriptInputName> <RunScriptInputName Condition="'$(TargetOS)' == 'MacCatalyst' or '$(TargetOS)' == 'iOS' or '$(TargetOS)' == 'iOSSimulator' or '$(TargetOS)' == 'tvOS' or '$(TargetOS)' == 'tvOSSimulator'">AppleRunnerTemplate.sh</RunScriptInputName>
<RunScriptInputName Condition="'$(TargetOS)' == 'Android'">AndroidRunnerTemplate.sh</RunScriptInputName> <RunScriptInputName Condition="'$(TargetOS)' == 'Android'">AndroidRunnerTemplate.sh</RunScriptInputName>
<RunScriptInputName Condition="'$(TargetOS)' == 'Browser' and '$(OS)' != 'Windows_NT'">WasmRunnerTemplate.sh</RunScriptInputName> <RunScriptInputName Condition="'$(TargetOS)' == 'Browser' and '$(OS)' != 'Windows_NT'">WasmRunnerTemplate.sh</RunScriptInputName>
<RunScriptInputName Condition="'$(TargetOS)' == 'Browser' and '$(OS)' == 'Windows_NT'">WasmRunnerTemplate.cmd</RunScriptInputName> <RunScriptInputName Condition="'$(TargetOS)' == 'Browser' and '$(OS)' == 'Windows_NT'">WasmRunnerTemplate.cmd</RunScriptInputName>
</PropertyGroup>
<RunScriptInputPath>$(MSBuildThisFileDirectory)$(RunScriptInputName)</RunScriptInputPath> <PropertyGroup>
<RunScriptInputPath Condition="'$(RunScriptInputPath)' == ''">$(MSBuildThisFileDirectory)$(RunScriptInputName)</RunScriptInputPath>
<RunScriptOutputName Condition="'$(TargetOS)' != 'windows'">RunTests.sh</RunScriptOutputName> <RunScriptOutputName Condition="'$(TargetOS)' != 'windows'">RunTests.sh</RunScriptOutputName>
<RunScriptOutputName Condition="'$(TargetOS)' == 'windows' or ('$(TargetOS)' == 'Browser' and '$(OS)' == 'Windows_NT')">RunTests.cmd</RunScriptOutputName> <RunScriptOutputName Condition="'$(TargetOS)' == 'windows' or ('$(TargetOS)' == 'Browser' and '$(OS)' == 'Windows_NT')">RunTests.cmd</RunScriptOutputName>
......
...@@ -311,7 +311,7 @@ ...@@ -311,7 +311,7 @@
<HelixCorrelationPayload Include="$(MonoAotCrossDir)" Destination="build/cross" /> <HelixCorrelationPayload Include="$(MonoAotCrossDir)" Destination="build/cross" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetOS)' == 'Browser'"> <ItemGroup Condition="'$(TargetOS)' == 'Browser' and '$(Scenario)' != 'BuildWasmApps'">
<HelixCorrelationPayload Include="$(TestEchoMiddleware)" Destination="xharness/TestEchoMiddleware" /> <HelixCorrelationPayload Include="$(TestEchoMiddleware)" Destination="xharness/TestEchoMiddleware" />
<HelixCorrelationPayload Include="$(RemoteLoopMiddleware)" Destination="xharness/RemoteLoopMiddleware" /> <HelixCorrelationPayload Include="$(RemoteLoopMiddleware)" Destination="xharness/RemoteLoopMiddleware" />
</ItemGroup> </ItemGroup>
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
<Import Project="$(MSBuildThisFileDirectory)WasmApp.props" /> <Import Project="$(MSBuildThisFileDirectory)WasmApp.props" />
<PropertyGroup> <PropertyGroup>
<!-- needed by the sdk, for net6.0, to include the correct runtime packs -->
<UseMonoRuntime>true</UseMonoRuntime>
<_NetCoreAppToolCurrent>net6.0</_NetCoreAppToolCurrent> <_NetCoreAppToolCurrent>net6.0</_NetCoreAppToolCurrent>
</PropertyGroup> </PropertyGroup>
......
...@@ -37,14 +37,14 @@ ...@@ -37,14 +37,14 @@
<DebuggerSupport>false</DebuggerSupport> <DebuggerSupport>false</DebuggerSupport>
</PropertyGroup> </PropertyGroup>
<!-- Redirect 'dotnet publish' to in-tree runtime pack --> <Target Name="UpdateTargetingAndRuntimePack" AfterTargets="ResolveFrameworkReferences" DependsOnTargets="_PrepareAndValidateWasmInputs">
<Target Name="TrickRuntimePackLocation" AfterTargets="ProcessFrameworkReferences" DependsOnTargets="_PrepareAndValidateWasmInputs">
<ItemGroup> <ItemGroup>
<RuntimePack> <RuntimePack>
<PackageDirectory>$(MicrosoftNetCoreAppRuntimePackLocationToUse)</PackageDirectory> <PackageDirectory>$(MicrosoftNetCoreAppRuntimePackLocationToUse)</PackageDirectory>
</RuntimePack> </RuntimePack>
<ResolvedRuntimePack PackageDirectory="$(MicrosoftNetCoreAppRuntimePackLocationToUse)" />
</ItemGroup> </ItemGroup>
<Message Text="Using Runtime pack from: %(RuntimePack.PackageDirectory)" Importance="high" /> <Message Text="Using Runtime pack from: %(ResolvedRuntimePack.PackageDirectory)" Importance="high" />
</Target> </Target>
<!-- the actual properties need to get set in the props, so because UsingTasks depend on those. --> <!-- the actual properties need to get set in the props, so because UsingTasks depend on those. -->
......
...@@ -31,11 +31,6 @@ ...@@ -31,11 +31,6 @@
<_ExeExt Condition="$([MSBuild]::IsOSPlatform('WINDOWS'))">.exe</_ExeExt> <_ExeExt Condition="$([MSBuild]::IsOSPlatform('WINDOWS'))">.exe</_ExeExt>
<WasmUseEMSDK_PATH Condition="'$(WasmUseEMSDK_PATH)' == '' and '$(EMSDK_PATH)' != '' and Exists('$(MSBuildThisFileDirectory)WasmApp.InTree.targets')">true</WasmUseEMSDK_PATH> <WasmUseEMSDK_PATH Condition="'$(WasmUseEMSDK_PATH)' == '' and '$(EMSDK_PATH)' != '' and Exists('$(MSBuildThisFileDirectory)WasmApp.InTree.targets')">true</WasmUseEMSDK_PATH>
<MicrosoftNetCoreAppRuntimePackDir Condition="'$(MicrosoftNetCoreAppRuntimePackDir)' == ''">$([MSBuild]::NormalizeDirectory($(NuGetPackageRoot), 'microsoft.netcore.app.runtime.mono.browser-wasm', '$(BundledNETCoreAppPackageVersion)'))</MicrosoftNetCoreAppRuntimePackDir>
<MicrosoftNetCoreAppRuntimePackRidDir Condition="'$(MicrosoftNetCoreAppRuntimePackRidDir)' == ''">$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackDir), 'runtimes', 'browser-wasm'))</MicrosoftNetCoreAppRuntimePackRidDir>
<MicrosoftNetCoreAppRuntimePackRidDir>$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackRidDir)))</MicrosoftNetCoreAppRuntimePackRidDir>
<MicrosoftNetCoreAppRuntimePackRidNativeDir>$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackRidDir), 'native'))</MicrosoftNetCoreAppRuntimePackRidNativeDir>
<_WasmRuntimePackIncludeDir>$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackRidNativeDir), 'include'))</_WasmRuntimePackIncludeDir> <_WasmRuntimePackIncludeDir>$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackRidNativeDir), 'include'))</_WasmRuntimePackIncludeDir>
<_WasmRuntimePackSrcDir>$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackRidNativeDir), 'src'))</_WasmRuntimePackSrcDir> <_WasmRuntimePackSrcDir>$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackRidNativeDir), 'src'))</_WasmRuntimePackSrcDir>
<_EmccPropsPath>$(_WasmRuntimePackSrcDir)Emcc.props</_EmccPropsPath> <_EmccPropsPath>$(_WasmRuntimePackSrcDir)Emcc.props</_EmccPropsPath>
...@@ -178,11 +173,6 @@ ...@@ -178,11 +173,6 @@
<_EmccCommonFlags Include="-v" Condition="'$(EmccVerbose)' != 'false'" /> <_EmccCommonFlags Include="-v" Condition="'$(EmccVerbose)' != 'false'" />
</ItemGroup> </ItemGroup>
<PropertyGroup>
<_WasmRuntimePackIncludeDir>$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackRidNativeDir), 'include'))</_WasmRuntimePackIncludeDir>
<_WasmRuntimePackSrcDir>$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackRidNativeDir), 'src'))</_WasmRuntimePackSrcDir>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<_DotnetJSSrcFile Include="$(_WasmRuntimePackSrcDir)\*.js" /> <_DotnetJSSrcFile Include="$(_WasmRuntimePackSrcDir)\*.js" />
</ItemGroup> </ItemGroup>
...@@ -361,6 +351,7 @@ EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_aot (const char *desc) { mono_ ...@@ -361,6 +351,7 @@ EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_aot (const char *desc) { mono_
<Target Name="_WasmAotCompileApp" Condition="'$(RunAOTCompilation)' == 'true'"> <Target Name="_WasmAotCompileApp" Condition="'$(RunAOTCompilation)' == 'true'">
<PropertyGroup> <PropertyGroup>
<!-- FIXME: do it once -->
<_MonoAotCrossCompilerPath>@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier','browser-wasm'))</_MonoAotCrossCompilerPath> <_MonoAotCrossCompilerPath>@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier','browser-wasm'))</_MonoAotCrossCompilerPath>
</PropertyGroup> </PropertyGroup>
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.IO;
using Xunit;
using Xunit.Abstractions;
#nullable enable
namespace Wasm.Build.Tests
{
public class BlazorWasmTests : BuildTestBase
{
public BlazorWasmTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
{
}
[ConditionalFact(typeof(BuildTestBase), nameof(IsUsingWorkloads))]
public void PublishTemplateProject()
{
InitPaths("id");
if (Directory.Exists(_projectDir))
Directory.Delete(_projectDir, recursive: true);
Directory.CreateDirectory(_projectDir);
Directory.CreateDirectory(Path.Combine(_projectDir, ".nuget"));
File.Copy(Path.Combine(BuildEnvironment.TestDataPath, "nuget6.config"), Path.Combine(_projectDir, "nuget.config"));
File.Copy(Path.Combine(BuildEnvironment.TestDataPath, "Blazor.Directory.Build.props"), Path.Combine(_projectDir, "Directory.Build.props"));
File.Copy(Path.Combine(BuildEnvironment.TestDataPath, "Blazor.Directory.Build.targets"), Path.Combine(_projectDir, "Directory.Build.targets"));
new DotNetCommand(s_buildEnv)
.WithWorkingDirectory(_projectDir)
.ExecuteWithCapturedOutput("new blazorwasm")
.EnsureSuccessful();
new DotNetCommand(s_buildEnv)
.WithWorkingDirectory(_projectDir)
.ExecuteWithCapturedOutput("publish -bl -p:RunAOTCompilation=true")
.EnsureSuccessful();
//TODO: validate the build somehow?
// compare dotnet.wasm?
// playwright?
}
}
}
// 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.Collections.Generic;
using System.IO;
namespace Wasm.Build.Tests
{
public class BuildEnvironment
{
public string DotNet { get; init; }
public string RuntimePackDir { get; init; }
public bool IsWorkload { get; init; }
public string DefaultBuildArgs { get; init; }
public IDictionary<string, string> EnvVars { get; init; }
public string DirectoryBuildPropsContents { get; init; }
public string DirectoryBuildTargetsContents { get; init; }
public string RuntimeNativeDir { get; init; }
public string LogRootPath { get; init; }
public static readonly string RelativeTestAssetsPath = @"..\testassets\";
public static readonly string TestAssetsPath = Path.Combine(AppContext.BaseDirectory, "testassets");
public static readonly string TestDataPath = Path.Combine(AppContext.BaseDirectory, "data");
private static string s_runtimeConfig = "Release";
private const string s_testLogPathEnvVar = "TEST_LOG_PATH";
public BuildEnvironment()
{
DirectoryInfo? solutionRoot = new (AppContext.BaseDirectory);
while (solutionRoot != null)
{
if (File.Exists(Path.Combine(solutionRoot.FullName, "NuGet.config")))
{
break;
}
solutionRoot = solutionRoot.Parent;
}
string? sdkForWorkloadPath = Environment.GetEnvironmentVariable("SDK_FOR_WORKLOAD_TESTING_PATH");
if (!string.IsNullOrEmpty(sdkForWorkloadPath))
{
DotNet = Path.Combine(sdkForWorkloadPath, "dotnet");
var workloadPacksVersion = Environment.GetEnvironmentVariable("WORKLOAD_PACKS_VER");
if (string.IsNullOrEmpty(workloadPacksVersion))
throw new Exception($"Cannot test with workloads without WORKLOAD_PACKS_VER environment variable being set");
RuntimePackDir = Path.Combine(sdkForWorkloadPath, "packs", "Microsoft.NETCore.App.Runtime.Mono.browser-wasm", workloadPacksVersion);
DirectoryBuildPropsContents = s_directoryBuildPropsForWorkloads;
DirectoryBuildTargetsContents = s_directoryBuildTargetsForWorkloads;
EnvVars = new Dictionary<string, string>()
{
// `runtime` repo's build environment sets these, and they
// mess up the build for the test project, which is using a different
// dotnet
["DOTNET_INSTALL_DIR"] = sdkForWorkloadPath,
["DOTNET_MULTILEVEL_LOOKUP"] = "0",
["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "1",
["MSBuildSDKsPath"] = string.Empty,
["PATH"] = $"{sdkForWorkloadPath}{Path.PathSeparator}{Environment.GetEnvironmentVariable("PATH")}"
};
var appRefDir = Environment.GetEnvironmentVariable("AppRefDir");
if (string.IsNullOrEmpty(appRefDir))
throw new Exception($"Cannot test with workloads without AppRefDir environment variable being set");
DefaultBuildArgs = $" /p:AppRefDir={appRefDir}";
IsWorkload = true;
}
else
{
string emsdkPath;
if (solutionRoot == null)
{
string? buildDir = Environment.GetEnvironmentVariable("WasmBuildSupportDir");
if (buildDir == null || !Directory.Exists(buildDir))
throw new Exception($"Could not find the solution root, or a build dir: {buildDir}");
emsdkPath = Path.Combine(buildDir, "emsdk");
RuntimePackDir = Path.Combine(buildDir, "microsoft.netcore.app.runtime.browser-wasm");
DefaultBuildArgs = $" /p:WasmBuildSupportDir={buildDir} /p:EMSDK_PATH={emsdkPath} ";
}
else
{
string artifactsBinDir = Path.Combine(solutionRoot.FullName, "artifacts", "bin");
RuntimePackDir = Path.Combine(artifactsBinDir, "microsoft.netcore.app.runtime.browser-wasm", s_runtimeConfig);
string? emsdkEnvValue = Environment.GetEnvironmentVariable("EMSDK_PATH");
if (string.IsNullOrEmpty(emsdkEnvValue))
emsdkPath = Path.Combine(solutionRoot.FullName, "src", "mono", "wasm", "emsdk");
else
emsdkPath = emsdkEnvValue;
DefaultBuildArgs = $" /p:RuntimeSrcDir={solutionRoot.FullName} /p:RuntimeConfig={s_runtimeConfig} /p:EMSDK_PATH={emsdkPath} ";
}
IsWorkload = false;
DotNet = "dotnet";
EnvVars = new Dictionary<string, string>()
{
["EMSDK_PATH"] = emsdkPath
};
DirectoryBuildPropsContents = s_directoryBuildPropsForLocal;
DirectoryBuildTargetsContents = s_directoryBuildTargetsForLocal;
}
RuntimeNativeDir = Path.Combine(RuntimePackDir, "runtimes", "browser-wasm", "native");
string? logPathEnvVar = Environment.GetEnvironmentVariable(s_testLogPathEnvVar);
if (!string.IsNullOrEmpty(logPathEnvVar))
{
LogRootPath = logPathEnvVar;
if (!Directory.Exists(LogRootPath))
{
Directory.CreateDirectory(LogRootPath);
}
}
else
{
LogRootPath = Environment.CurrentDirectory;
}
}
// FIXME: update these to use Workload variants of the file, with the workload support
protected static string s_directoryBuildPropsForWorkloads = File.ReadAllText(Path.Combine(TestDataPath, "Local.Directory.Build.props"));
protected static string s_directoryBuildTargetsForWorkloads = File.ReadAllText(Path.Combine(TestDataPath, "Local.Directory.Build.targets"));
protected static string s_directoryBuildPropsForLocal = File.ReadAllText(Path.Combine(TestDataPath, "Local.Directory.Build.props"));
protected static string s_directoryBuildTargetsForLocal = File.ReadAllText(Path.Combine(TestDataPath, "Local.Directory.Build.targets"));
}
}
// 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.Diagnostics;
using System.Text;
using Xunit.Sdk;
namespace Wasm.Build.Tests
{
// taken from https://github.com/dotnet/arcade/blob/main/src/Common/Microsoft.Arcade.Common/CommandResult.cs
public struct CommandResult
{
public static readonly CommandResult Empty = new CommandResult();
public ProcessStartInfo StartInfo { get; }
public int ExitCode { get; }
public string Output { get; }
public CommandResult(ProcessStartInfo startInfo, int exitCode, string output)
{
StartInfo = startInfo;
ExitCode = exitCode;
Output = output;
}
public void EnsureSuccessful(string messagePrefix = "", bool suppressOutput = false)
{
if (ExitCode != 0)
{
StringBuilder message = new StringBuilder($"{messagePrefix} Command failed with exit code {ExitCode}: {StartInfo.FileName} {StartInfo.Arguments}");
if (!suppressOutput)
{
if (!string.IsNullOrEmpty(Output))
{
message.AppendLine($"{Environment.NewLine}Standard Output:{Environment.NewLine}{Output}");
}
}
throw new XunitException(message.ToString());
}
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace Wasm.Build.Tests
{
public class DotNetCommand : ToolCommand
{
private BuildEnvironment _buildEnvironment;
public DotNetCommand(BuildEnvironment buildEnv) : base(buildEnv.DotNet)
{
_buildEnvironment = buildEnv;
WithEnvironmentVariables(buildEnv.EnvVars);
}
protected override string GetFullArgs(params string[] args)
=> $"{_buildEnvironment.DefaultBuildArgs} {string.Join(" ", args)}";
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.IO;
using Xunit;
using Xunit.Abstractions;
#nullable enable
namespace Wasm.Build.Tests
{
public class LocalEMSDKTests : BuildTestBase
{
public LocalEMSDKTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext)
{}
[ConditionalTheory(typeof(BuildTestBase), nameof(IsNotUsingWorkloads))]
[BuildAndRun(aot: true, host: RunHost.None, parameters: new object[]
{ "", "error :.*emscripten.*required for AOT" })]
[BuildAndRun(aot: true, host: RunHost.None, parameters: new object[]
{ "/non-existant/foo", "error.*\\(EMSDK_PATH\\)=/non-existant/foo.*required for AOT" })]
public void AOT_ErrorWhenMissingEMSDK(BuildArgs buildArgs, string emsdkPath, string errorPattern, string id)
{
string projectName = $"missing_emsdk";
buildArgs = buildArgs with {
ProjectName = projectName,
ExtraBuildArgs = $"/p:EMSDK_PATH={emsdkPath}"
};
buildArgs = ExpandBuildArgs(buildArgs);
(_, string buildOutput) = BuildProject(buildArgs,
initProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
id: id,
expectSuccess: false);
Assert.Matches(errorPattern, buildOutput);
}
[ConditionalTheory(typeof(BuildTestBase), nameof(IsNotUsingWorkloads))]
[BuildAndRun(host: RunHost.None, parameters: new object[]
{ "", "error.*emscripten.*required for building native files" })]
[BuildAndRun(host: RunHost.None, parameters: new object[]
{ "/non-existant/foo", "error.*\\(EMSDK_PATH\\)=/non-existant/foo.*required for building native files" })]
public void Relinking_ErrorWhenMissingEMSDK(BuildArgs buildArgs, string emsdkPath, string errorPattern, string id)
{
string projectName = $"simple_native_build";
buildArgs = buildArgs with {
ProjectName = projectName,
ExtraBuildArgs = $"/p:EMSDK_PATH={emsdkPath}"
};
buildArgs = ExpandBuildArgs(buildArgs, extraProperties: "<WasmBuildNative>true</WasmBuildNative>");
(_, string buildOutput) = BuildProject(buildArgs,
initProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
id: id,
expectSuccess: false);
Assert.Matches(errorPattern, buildOutput);
}
}
}
...@@ -27,27 +27,7 @@ public NativeBuildTests(ITestOutputHelper output, SharedBuildPerTestClassFixture ...@@ -27,27 +27,7 @@ public NativeBuildTests(ITestOutputHelper output, SharedBuildPerTestClassFixture
public void SimpleNativeBuild(BuildArgs buildArgs, RunHost host, string id) public void SimpleNativeBuild(BuildArgs buildArgs, RunHost host, string id)
=> NativeBuild("simple_native_build", s_mainReturns42, buildArgs, host, id); => NativeBuild("simple_native_build", s_mainReturns42, buildArgs, host, id);
[Theory]
[BuildAndRun(host: RunHost.None, parameters: new object[]
{ "", "error.*emscripten.*required for building native files" })]
[BuildAndRun(host: RunHost.None, parameters: new object[]
{ "/non-existant/foo", "error.*\\(EMSDK_PATH\\)=/non-existant/foo.*required for building native files" })]
public void Relinking_ErrorWhenMissingEMSDK(BuildArgs buildArgs, string emsdkPath, string errorPattern, string id)
{
string projectName = $"simple_native_build";
buildArgs = buildArgs with {
ProjectName = projectName,
ExtraBuildArgs = $"/p:EMSDK_PATH={emsdkPath}"
};
buildArgs = ExpandBuildArgs(buildArgs, extraProperties: "<WasmBuildNative>true</WasmBuildNative>");
(_, string buildOutput) = BuildProject(buildArgs,
initProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
id: id,
expectSuccess: false);
Assert.Matches(errorPattern, buildOutput);
}
private void NativeBuild(string projectNamePrefix, string projectContents, BuildArgs buildArgs, RunHost host, string id) private void NativeBuild(string projectNamePrefix, string projectContents, BuildArgs buildArgs, RunHost host, string id)
{ {
......
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace Wasm.Build.Tests
{
internal static class ProcessExtensions
{
#if NET451
private static readonly bool _isWindows = true;
#else
private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#endif
private static readonly TimeSpan _defaultTimeout = TimeSpan.FromSeconds(30);
public static void KillTree(this Process process)
{
process.KillTree(_defaultTimeout);
}
public static void KillTree(this Process process, TimeSpan timeout)
{
string stdout;
if (_isWindows)
{
RunProcessAndWaitForExit(
"taskkill",
$"/T /F /PID {process.Id}",
timeout,
out stdout);
}
else
{
var children = new HashSet<int>();
GetAllChildIdsUnix(process.Id, children, timeout);
foreach (var childId in children)
{
KillProcessUnix(childId, timeout);
}
KillProcessUnix(process.Id, timeout);
}
}
private static void GetAllChildIdsUnix(int parentId, ISet<int> children, TimeSpan timeout)
{
string stdout;
var exitCode = RunProcessAndWaitForExit(
"pgrep",
$"-P {parentId}",
timeout,
out stdout);
if (exitCode == 0 && !string.IsNullOrEmpty(stdout))
{
using (var reader = new StringReader(stdout))
{
while (true)
{
var text = reader.ReadLine();
if (text == null)
{
return;
}
int id;
if (int.TryParse(text, out id))
{
children.Add(id);
// Recursively get the children
GetAllChildIdsUnix(id, children, timeout);
}
}
}
}
}
private static void KillProcessUnix(int processId, TimeSpan timeout)
{
string stdout;
RunProcessAndWaitForExit(
"kill",
$"-TERM {processId}",
timeout,
out stdout);
}
private static int RunProcessAndWaitForExit(string fileName, string arguments, TimeSpan timeout, out string stdout)
{
var startInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
RedirectStandardOutput = true,
UseShellExecute = false
};
var process = Process.Start(startInfo);
stdout = null;
if (process.WaitForExit((int)timeout.TotalMilliseconds))
{
stdout = process.StandardOutput.ReadToEnd();
}
else
{
process.Kill();
}
return process.ExitCode;
}
public static Task StartAndWaitForExitAsync(this Process subject)
{
var taskCompletionSource = new TaskCompletionSource<object>();
subject.EnableRaisingEvents = true;
subject.Exited += (s, a) =>
{
taskCompletionSource.SetResult(null);
subject.Dispose();
};
subject.Start();
return taskCompletionSource.Task;
}
}
}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
using System.IO; using System.IO;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
using Xunit.Sdk;
#nullable enable #nullable enable
...@@ -38,7 +39,7 @@ public void NoOpRebuild(BuildArgs buildArgs, bool nativeRelink, RunHost host, st ...@@ -38,7 +39,7 @@ public void NoOpRebuild(BuildArgs buildArgs, bool nativeRelink, RunHost host, st
Run(); Run();
if (!_buildContext.TryGetBuildFor(buildArgs, out BuildProduct? product)) if (!_buildContext.TryGetBuildFor(buildArgs, out BuildProduct? product))
Assert.True(false, $"Test bug: could not get the build product in the cache"); throw new XunitException($"Test bug: could not get the build product in the cache");
File.Move(product!.LogFile, Path.ChangeExtension(product.LogFile!, ".first.binlog")); File.Move(product!.LogFile, Path.ChangeExtension(product.LogFile!, ".first.binlog"));
...@@ -46,9 +47,8 @@ public void NoOpRebuild(BuildArgs buildArgs, bool nativeRelink, RunHost host, st ...@@ -46,9 +47,8 @@ public void NoOpRebuild(BuildArgs buildArgs, bool nativeRelink, RunHost host, st
// no-op Rebuild // no-op Rebuild
BuildProject(buildArgs, BuildProject(buildArgs,
() => {},
dotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack,
id: id, id: id,
dotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack,
createProject: false, createProject: false,
useCache: false); useCache: false);
......
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
...@@ -44,11 +45,14 @@ public SatelliteAssembliesTests(ITestOutputHelper output, SharedBuildPerTestClas ...@@ -44,11 +45,14 @@ public SatelliteAssembliesTests(ITestOutputHelper output, SharedBuildPerTestClas
buildArgs = buildArgs with { ProjectName = projectName }; buildArgs = buildArgs with { ProjectName = projectName };
buildArgs = ExpandBuildArgs(buildArgs, buildArgs = ExpandBuildArgs(buildArgs,
projectTemplate: s_resourcesProjectTemplate, projectTemplate: s_resourcesProjectTemplate,
extraProperties: $"<WasmBuildNative>{(nativeRelink ? "true" : "false")}</WasmBuildNative>", extraProperties: $"<WasmBuildNative>{(nativeRelink ? "true" : "false")}</WasmBuildNative>");
extraItems: $"<EmbeddedResource Include=\"..\\resx\\*\" />");
BuildProject(buildArgs, BuildProject(buildArgs,
initProject: () => CreateProgramForCultureTest($"{projectName}.words", "TestClass"), initProject: () =>
{
Utils.DirectoryCopy(Path.Combine(BuildEnvironment.TestAssetsPath, "resx"), Path.Combine(_projectDir!, "resx"));
CreateProgramForCultureTest(_projectDir!, $"{projectName}.resx.words", "TestClass");
},
dotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack, dotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack,
id: id); id: id);
...@@ -71,7 +75,7 @@ public SatelliteAssembliesTests(ITestOutputHelper output, SharedBuildPerTestClas ...@@ -71,7 +75,7 @@ public SatelliteAssembliesTests(ITestOutputHelper output, SharedBuildPerTestClas
RunHost host, RunHost host,
string id) string id)
{ {
string projectName = $"sat_asm_proj_ref"; string projectName = $"SatelliteAssemblyFromProjectRef";
bool dotnetWasmFromRuntimePack = !nativeRelink && !buildArgs.AOT; bool dotnetWasmFromRuntimePack = !nativeRelink && !buildArgs.AOT;
buildArgs = buildArgs with { ProjectName = projectName }; buildArgs = buildArgs with { ProjectName = projectName };
...@@ -81,9 +85,17 @@ public SatelliteAssembliesTests(ITestOutputHelper output, SharedBuildPerTestClas ...@@ -81,9 +85,17 @@ public SatelliteAssembliesTests(ITestOutputHelper output, SharedBuildPerTestClas
extraItems: $"<ProjectReference Include=\"..\\LibraryWithResources\\LibraryWithResources.csproj\" />"); extraItems: $"<ProjectReference Include=\"..\\LibraryWithResources\\LibraryWithResources.csproj\" />");
BuildProject(buildArgs, BuildProject(buildArgs,
initProject: () => CreateProgramForCultureTest("LibraryWithResources.words", "LibraryWithResources.Class1"),
dotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack, dotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack,
id: id); id: id,
initProject: () =>
{
string rootDir = _projectDir!;
_projectDir = Path.Combine(rootDir, projectName);
Directory.CreateDirectory(_projectDir);
Utils.DirectoryCopy(Path.Combine(BuildEnvironment.TestAssetsPath, "SatelliteAssemblyFromProjectRef"), rootDir);
CreateProgramForCultureTest(_projectDir, "LibraryWithResources.resx.words", "LibraryWithResources.Class1");
});
string output = RunAndTestWasmApp(buildArgs, string output = RunAndTestWasmApp(buildArgs,
expectedExitCode: 42, expectedExitCode: 42,
...@@ -105,11 +117,10 @@ public void CheckThatSatelliteAssembliesAreNotAOTed(BuildArgs buildArgs, string ...@@ -105,11 +117,10 @@ public void CheckThatSatelliteAssembliesAreNotAOTed(BuildArgs buildArgs, string
extraProperties: $@" extraProperties: $@"
<EmccCompileOptimizationFlag>-O0</EmccCompileOptimizationFlag> <EmccCompileOptimizationFlag>-O0</EmccCompileOptimizationFlag>
<EmccLinkOptimizationFlag>-O0</EmccLinkOptimizationFlag>", <EmccLinkOptimizationFlag>-O0</EmccLinkOptimizationFlag>",
extraItems: $"<EmbeddedResource Include=\"..\\resx\\*\" />"); extraItems: $"<EmbeddedResource Include=\"{BuildEnvironment.RelativeTestAssetsPath}resx\\*\" />");
System.Console.WriteLine ($"--- aot: {buildArgs.AOT}");
BuildProject(buildArgs, BuildProject(buildArgs,
initProject: () => CreateProgramForCultureTest($"{projectName}.words", "TestClass"), initProject: () => CreateProgramForCultureTest(_projectDir!, $"{projectName}.words", "TestClass"),
dotnetWasmFromRuntimePack: false, dotnetWasmFromRuntimePack: false,
id: id); id: id);
...@@ -124,8 +135,8 @@ public void CheckThatSatelliteAssembliesAreNotAOTed(BuildArgs buildArgs, string ...@@ -124,8 +135,8 @@ public void CheckThatSatelliteAssembliesAreNotAOTed(BuildArgs buildArgs, string
} }
#pragma warning restore xUnit1026 #pragma warning restore xUnit1026
private void CreateProgramForCultureTest(string resourceName, string typeName) private void CreateProgramForCultureTest(string dir, string resourceName, string typeName)
=> File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), => File.WriteAllText(Path.Combine(dir, "Program.cs"),
s_cultureResourceTestProgram s_cultureResourceTestProgram
.Replace("##RESOURCE_NAME##", resourceName) .Replace("##RESOURCE_NAME##", resourceName)
.Replace("##TYPE_NAME##", typeName)); .Replace("##TYPE_NAME##", typeName));
......
...@@ -44,7 +44,7 @@ private void RemoveDirectory(string path) ...@@ -44,7 +44,7 @@ private void RemoveDirectory(string path)
{ {
try try
{ {
Directory.Delete(path, recursive: true); Directory.Delete(path, recursive: true);
} }
catch (Exception ex) catch (Exception ex)
{ {
......
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
#nullable enable
namespace Wasm.Build.Tests
{
public class ToolCommand
{
private string _label;
protected string _command;
public Process? CurrentProcess { get; private set; }
public Dictionary<string, string> Environment { get; } = new Dictionary<string, string>();
public event DataReceivedEventHandler? ErrorDataReceived;
public event DataReceivedEventHandler? OutputDataReceived;
public string? WorkingDirectory { get; set; }
public ToolCommand(string command, string label="")
{
_command = command;
_label = label;
}
public ToolCommand WithWorkingDirectory(string dir)
{
WorkingDirectory = dir;
return this;
}
public ToolCommand WithEnvironmentVariable(string key, string value)
{
Environment[key] = value;
return this;
}
public ToolCommand WithEnvironmentVariables(IDictionary<string, string>? extraEnvVars)
{
if (extraEnvVars != null)
{
foreach ((string key, string value) in extraEnvVars)
Environment[key] = value;
}
return this;
}
public virtual CommandResult Execute(params string[] args)
{
return Task.Run(async () => await ExecuteAsync(args)).Result;
}
public async virtual Task<CommandResult> ExecuteAsync(params string[] args)
{
var resolvedCommand = _command;
string fullArgs = GetFullArgs(args);
Console.WriteLine($"[{_label}] Executing - {resolvedCommand} {fullArgs} - {WorkingDirectoryInfo()}");
return await ExecuteAsyncInternal(resolvedCommand, fullArgs);
}
public virtual CommandResult ExecuteWithCapturedOutput(params string[] args)
{
var resolvedCommand = _command;
string fullArgs = GetFullArgs(args);
Console.WriteLine($"[{_label}] Executing (Captured Output) - {resolvedCommand} {fullArgs} - {WorkingDirectoryInfo()}");
return Task.Run(async () => await ExecuteAsyncInternal(resolvedCommand, fullArgs)).Result;
}
protected virtual string GetFullArgs(params string[] args) => string.Join(" ", args);
private async Task<CommandResult> ExecuteAsyncInternal(string executable, string args)
{
var output = new List<string>();
CurrentProcess = CreateProcess(executable, args);
CurrentProcess.ErrorDataReceived += (s, e) =>
{
if (e.Data == null)
return;
output.Add($"[{_label}] {e.Data}");
ErrorDataReceived?.Invoke(s, e);
};
CurrentProcess.OutputDataReceived += (s, e) =>
{
if (e.Data == null)
return;
output.Add($"[{_label}] {e.Data}");
OutputDataReceived?.Invoke(s, e);
};
var completionTask = CurrentProcess.StartAndWaitForExitAsync();
CurrentProcess.BeginOutputReadLine();
CurrentProcess.BeginErrorReadLine();
await completionTask;
CurrentProcess.WaitForExit();
RemoveNullTerminator(output);
return new CommandResult(
CurrentProcess.StartInfo,
CurrentProcess.ExitCode,
string.Join(System.Environment.NewLine, output));
}
private Process CreateProcess(string executable, string args)
{
var psi = new ProcessStartInfo
{
FileName = executable,
Arguments = args,
RedirectStandardError = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
UseShellExecute = false
};
psi.Environment["DOTNET_MULTILEVEL_LOOKUP"] = "0";
psi.Environment["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "1";
AddEnvironmentVariablesTo(psi);
AddWorkingDirectoryTo(psi);
var process = new Process
{
StartInfo = psi
};
process.EnableRaisingEvents = true;
return process;
}
private string WorkingDirectoryInfo()
{
if (WorkingDirectory == null)
{
return "";
}
return $" in pwd {WorkingDirectory}";
}
private void RemoveNullTerminator(List<string> strings)
{
var count = strings.Count;
if (count < 1)
{
return;
}
if (strings[count - 1] == null)
{
strings.RemoveAt(count - 1);
}
}
private void AddEnvironmentVariablesTo(ProcessStartInfo psi)
{
foreach (var item in Environment)
{
psi.Environment[item.Key] = item.Value;
}
}
private void AddWorkingDirectoryTo(ProcessStartInfo psi)
{
if (!string.IsNullOrWhiteSpace(WorkingDirectory))
{
psi.WorkingDirectory = WorkingDirectory;
}
}
}
}
// 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.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
internal static class Utils
{
public static void DirectoryCopy(string sourceDirName, string destDirName, Func<string, bool>? predicate=null, bool copySubDirs=true, bool silent=false)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
Directory.CreateDirectory(destDirName);
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string fullPath = file.ToString();
if (predicate != null && !predicate(fullPath))
{
// if (!silent)
// e(MessageImportance.Low, $"Skipping {fullPath}");
continue;
}
string tempPath = Path.Combine(destDirName, file.Name);
// if (!silent)
// Logger?.LogMessage(MessageImportance.Low, $"Copying {fullPath} to {tempPath}");
file.CopyTo(tempPath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string tempPath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, tempPath, predicate, copySubDirs, silent);
}
}
}
}
...@@ -13,31 +13,53 @@ ...@@ -13,31 +13,53 @@
<DefineConstants Condition="'$(ContinuousIntegrationBuild)' != 'true'">TEST_DEBUG_CONFIG_ALSO</DefineConstants> <DefineConstants Condition="'$(ContinuousIntegrationBuild)' != 'true'">TEST_DEBUG_CONFIG_ALSO</DefineConstants>
<!-- This project should not build against the live built .NETCoreApp targeting pack as it contributes to the build itself. --> <!-- This project should not build against the live built .NETCoreApp targeting pack as it contributes to the build itself. -->
<UseLocalTargetingRuntimePack>false</UseLocalTargetingRuntimePack> <UseLocalTargetingRuntimePack>false</UseLocalTargetingRuntimePack>
<TestUsingWorkloads Condition="'$(TestUsingWorkloads)' == ''">true</TestUsingWorkloads>
<!-- don't run any wasm build steps --> <!-- don't run any wasm build steps -->
<WasmBuildAppAfterThisTarget /> <WasmBuildAppAfterThisTarget />
</PropertyGroup> <RunScriptInputName>RunScriptTemplate.sh</RunScriptInputName>
<RunScriptInputPath>$(MSBuildThisFileDirectory)data\$(RunScriptInputName)</RunScriptInputPath>
<PropertyGroup Condition="'$(ContinuousIntegrationBuild)' == 'true'">
<_PreCommand Condition="'$(OS)' != 'Windows_NT'">WasmBuildSupportDir=%24{HELIX_CORRELATION_PAYLOAD}/build</_PreCommand>
<_PreCommand Condition="'$(OS)' == 'Windows_NT'">set WasmBuildSupportDir=%HELIX_CORRELATION_PAYLOAD%/build &amp;</_PreCommand>
</PropertyGroup>
<PropertyGroup>
<_PreCommand Condition="'$(OS)' != 'Windows_NT'">$(_PreCommand) TEST_LOG_PATH=%24{XHARNESS_OUT}/logs</_PreCommand>
<_PreCommand Condition="'$(OS)' != 'Windows_NT'">$(_PreCommand) HARNESS_RUNNER=%24{HARNESS_RUNNER}</_PreCommand>
<_PreCommand Condition="'$(OS)' == 'Windows_NT'">$(_PreCommand) set TEST_LOG_PATH=%XHARNESS_OUT%\logs &amp;</_PreCommand>
<_PreCommand Condition="'$(OS)' == 'Windows_NT'">$(_PreCommand) set HARNESS_RUNNER=%HARNESS_RUNNER% &amp;</_PreCommand>
<RunScriptCommand Condition="'$(OS)' != 'Windows_NT'">$(_PreCommand) dotnet exec xunit.console.dll $(AssemblyName).dll -xml %24XHARNESS_OUT/testResults.xml</RunScriptCommand>
<RunScriptCommand Condition="'$(OS)' == 'Windows_NT'">$(_PreCommand) dotnet.exe exec xunit.console.dll $(AssemblyName).dll -xml %XHARNESS_OUT%\testResults.xml</RunScriptCommand>
<RunScriptCommand Condition="'$(ContinuousIntegrationBuild)' == 'true'">$(RunScriptCommand) -nocolor</RunScriptCommand>
<RunScriptCommand Condition="'$(ContinuousIntegrationBuild)' == 'true' or '$(XUnitShowProgress)' == 'true'">$(RunScriptCommand) -verbose</RunScriptCommand>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Include="$(RepoRoot)\src\mono\wasm\runtime-test.js" CopyToOutputDirectory="PreserveNewest" /> <None Include="$(RepoRoot)\src\mono\wasm\runtime-test.js" CopyToOutputDirectory="PreserveNewest" />
<None Include="..\testassets\**\*" Link="testassets\%(RecursiveDir)%(FileName)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
<None Include="..\testassets\**\*" CopyToOutputDirectory="PreserveNewest" /> <None Include="data\**\*" Link="data\%(RecursiveDir)%(FileName)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup> </ItemGroup>
<Target Name="UpdateRunScriptCommands" BeforeTargets="GenerateRunScript">
<ItemGroup>
<RunScriptCommands Condition="'$(OS)' != 'Windows_NT'" Include="export WORKLOAD_PACKS_VER=$(Version)" />
<RunScriptCommands Condition="'$(OS)' == 'Windows_NT'" Include="set WORKLOAD_PACKS_VER=$(Version)" />
</ItemGroup>
<ItemGroup Condition="'$(ContinuousIntegrationBuild)' == 'true'">
<!-- TEST_USING_WORKLOADS - this is set per helix job, in sendtohelixhelp.proj -->
<RunScriptCommands Condition="'$(OS)' != 'Windows_NT'" Include="export BASE_DIR=%24{HELIX_CORRELATION_PAYLOAD}" />
<RunScriptCommands Condition="'$(OS)' == 'Windows_NT'" Include="set BASE_DIR=%HELIX_CORRELATION_PAYLOAD%" />
</ItemGroup>
<ItemGroup Condition="'$(ContinuousIntegrationBuild)' != 'true'">
<!-- Enable once we add workloads based testing -->
<!--<RunScriptCommands Condition="'$(OS)' != 'Windows_NT'" Include="export TEST_USING_WORKLOADS=$(TestUsingWorkloads)" />-->
<!--<RunScriptCommands Condition="'$(OS)' == 'Windows_NT'" Include="set TEST_USING_WORKLOADS=$(TestUsingWorkloads)" />-->
<RunScriptCommands Condition="'$(OS)' != 'Windows_NT'" Include="export BASE_DIR=$(ArtifactsBinDir)" />
<RunScriptCommands Condition="'$(OS)' == 'Windows_NT'" Include="set BASE_DIR=$(ArtifactsBinDir)" />
</ItemGroup>
<ItemGroup>
<RunScriptCommands Condition="'$(OS)' != 'Windows_NT'" Include="set_env_vars" />
</ItemGroup>
<PropertyGroup>
<RunScriptCommand Condition="'$(OS)' != 'Windows_NT'">dotnet exec xunit.console.dll $(AssemblyName).dll -xml %24XHARNESS_OUT/testResults.xml</RunScriptCommand>
<RunScriptCommand Condition="'$(OS)' == 'Windows_NT'">dotnet.exe exec xunit.console.dll $(AssemblyName).dll -xml %XHARNESS_OUT%\testResults.xml</RunScriptCommand>
<RunScriptCommand Condition="'$(ContinuousIntegrationBuild)' == 'true'">$(RunScriptCommand) -nocolor</RunScriptCommand>
<RunScriptCommand Condition="'$(ContinuousIntegrationBuild)' == 'true' or '$(XUnitShowProgress)' == 'true'">$(RunScriptCommand) -verbose</RunScriptCommand>
<RunScriptCommand Condition="'$(XUnitMethodName)' != ''">$(RunScriptCommand) -method $(XUnitMethodName)</RunScriptCommand>
<RunScriptCommand Condition="'$(XUnitClassName)' != ''">$(RunScriptCommand) -class $(XUnitClassName)</RunScriptCommand>
</PropertyGroup>
</Target>
</Project> </Project>
...@@ -60,28 +60,6 @@ public static int Main() ...@@ -60,28 +60,6 @@ public static int Main()
} }
}", buildArgs, host, id); }", buildArgs, host, id);
[Theory]
[BuildAndRun(aot: true, host: RunHost.None, parameters: new object[]
{ "", "error :.*emscripten.*required for AOT" })]
[BuildAndRun(aot: true, host: RunHost.None, parameters: new object[]
{ "/non-existant/foo", "error.*\\(EMSDK_PATH\\)=/non-existant/foo.*required for AOT" })]
public void AOT_ErrorWhenMissingEMSDK(BuildArgs buildArgs, string emsdkPath, string errorPattern, string id)
{
string projectName = $"missing_emsdk";
buildArgs = buildArgs with {
ProjectName = projectName,
ExtraBuildArgs = $"/p:EMSDK_PATH={emsdkPath}"
};
buildArgs = ExpandBuildArgs(buildArgs);
(_, string buildOutput) = BuildProject(buildArgs,
initProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
id: id,
expectSuccess: false);
Assert.Matches(errorPattern, buildOutput);
}
private static string s_bug49588_ProgramCS = @" private static string s_bug49588_ProgramCS = @"
using System; using System;
public class TestClass { public class TestClass {
......
// 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 System.Linq;
using System.Xml;
using System.Xml.Serialization;
using Xunit;
using Xunit.Abstractions;
#nullable enable
namespace Wasm.Build.Tests
{
public class WorkloadTests : BuildTestBase
{
public WorkloadTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
{
}
[ConditionalFact(typeof(BuildTestBase), nameof(IsUsingWorkloads))]
public void FilesInUnixFilesPermissionsXmlExist()
{
// not doing any project generation here
_enablePerTestCleanup = false;
// find all the UnixFilePermissions ..
string packsDir = Path.Combine(Path.GetDirectoryName(s_buildEnv.DotNet)!, "packs");
Assert.True(Directory.Exists(packsDir), $"Could not find packs directory {packsDir}");
var unixPermFiles = Directory.EnumerateFiles(packsDir, "UnixFilePermissions.xml", new EnumerationOptions { RecurseSubdirectories = true });
foreach (string unixPermFile in unixPermFiles)
{
Assert.True(File.Exists(unixPermFile), $"Could not find {unixPermFile}");
FileList? list = FileList.Deserialize(unixPermFile);
if (list == null)
throw new Exception($"Could not read unix permissions file {unixPermFile}");
// File is in <packs>/<packName>/<version>/data/UnixFilePermissions.xml
// and <FileList><File Path="tools/bin/2to3" Permission="755" />
string thisPackDir = Path.Combine(Path.GetDirectoryName(unixPermFile)!, "..");
foreach (FileListFile flf in list.File)
{
if (flf.Path == null)
throw new Exception($"Path for FileListFile should not be null. xml: {unixPermFile}");
var targetFile = Path.Combine(thisPackDir, flf.Path);
Assert.True(File.Exists(targetFile), $"Expected file {targetFile} to exist in the pack, as it is referenced in {unixPermFile}");
}
}
// We don't install the cross compiler pack from nupkg, so we don't
// have the unixFilePermissions for that
// Expect just the emscripten ones here for now
Assert.Equal(3, unixPermFiles.Count());
}
}
[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class FileList
{
private FileListFile[]? fileField;
[XmlElement("File")]
public FileListFile[] File
{
get => fileField ?? Array.Empty<FileListFile>();
set => fileField = value;
}
public static FileList? Deserialize(string pathToXml)
{
var serializer = new XmlSerializer(typeof(FileList));
using var fs = new FileStream(pathToXml, FileMode.Open, FileAccess.Read);
var reader = XmlReader.Create(fs);
FileList? fileList = (FileList?)serializer.Deserialize(reader);
return fileList;
}
}
// From https://github.com/dotnet/sdk/blob/main/src/Cli/dotnet/NugetPackageDownloader/WorkloadUnixFilePermissionsFileList.cs
[Serializable]
[XmlType(AnonymousType = true)]
public class FileListFile
{
private string? pathField;
private string? permissionField;
[XmlAttribute]
public string? Path
{
get => pathField;
set => pathField = value;
}
[XmlAttribute]
public string? Permission
{
get => permissionField;
set => permissionField = value;
}
}
}
<Project>
<PropertyGroup>
<_MicrosoftNetCoreAppRefDir>$(AppRefDir)\</_MicrosoftNetCoreAppRefDir>
<LocalFrameworkOverrideName>Microsoft.NETCore.App</LocalFrameworkOverrideName>
</PropertyGroup>
<Target Name="PrintRuntimePackPath" BeforeTargets="Publish">
<Message Text="** MicrosoftNetCoreAppRuntimePackDir : $(MicrosoftNetCoreAppRuntimePackDir)" Importance="High" />
</Target>
<!-- SDK tries to download runtime packs when RuntimeIdentifier is set, remove them from PackageDownload item. -->
<Target Name="RemoveRuntimePackFromDownloadItem"
AfterTargets="ProcessFrameworkReferences">
<ItemGroup>
<PackageDownload Remove="@(PackageDownload)"
Condition="'$(UsePackageDownload)' == 'true' and $([System.String]::Copy('%(Identity)').StartsWith('Microsoft.NETCore.App.Runtime'))" />
<PackageReference Remove="@(PackageReference)"
Condition="'$(UsePackageDownload)' != 'true' and $([System.String]::Copy('%(Identity)').StartsWith('Microsoft.NETCore.App.Runtime'))" />
</ItemGroup>
</Target>
<!-- Use local targeting pack for NetCoreAppCurrent. -->
<Target Name="UpdateTargetingAndRuntimePack"
AfterTargets="ResolveFrameworkReferences">
<ItemGroup>
<ResolvedTargetingPack Path="$(_MicrosoftNetCoreAppRefDir.TrimEnd('/\'))"
NuGetPackageVersion="$(RuntimePackInWorkloadVersion)"
PackageDirectory="$(_MicrosoftNetCoreAppRefDir.TrimEnd('/\'))"
Condition="'%(ResolvedTargetingPack.RuntimeFrameworkName)' == 'Microsoft.NETCore.App' and
Exists('$(_MicrosoftNetCoreAppRefDir)data\FrameworkList.xml')" />
<ResolvedRuntimePack
Update="Microsoft.NETCore.App.Runtime.Mono.browser-wasm"
FrameworkName="Microsoft.NETCore.App"
NuGetPackageId="Microsoft.NETCore.App.Runtime.Mono.browser-wasm"
NuGetPackageVersion="$(RuntimePackInWorkloadVersion)"
PackageDirectory="$(WorkloadPacksDir)\Microsoft.NETCore.App.Runtime.Mono.browser-wasm\$(RuntimePackInWorkloadVersion)"
RuntimeIdentifier="browser-wasm" />
<ResolvedFrameworkReference
TargetingPackPath="$(_MicrosoftNetCoreAppRefDir.TrimEnd('/\'))"
Include="Microsoft.NETCore.App"
RuntimePackName="Microsoft.NETCore.App.Runtime.Mono.browser-wasm"
RuntimePackVersion="$(RuntimePackInWorkloadVersion)"
RuntimePackPath="$(WorkloadPacksDir)\Microsoft.NETCore.App.Runtime.Mono.browser-wasm\$(RuntimePackInWorkloadVersion)"
RuntimeIdentifier="browser-wasm" />
</ItemGroup>
</Target>
<!-- Update the local targeting pack's version as it's written into the runtimeconfig.json file to select the right framework. -->
<Target Name="UpdateRuntimeFrameworkVersion"
AfterTargets="ResolveTargetingPackAssets">
<ItemGroup>
<RuntimeFramework Version="$(RuntimePackInWorkloadVersion)"
Condition="'%(RuntimeFramework.FrameworkName)' == 'Microsoft.NETCore.App'" />
</ItemGroup>
</Target>
<!-- Filter out conflicting implicit assembly references. -->
<Target Name="FilterImplicitAssemblyReferences"
Condition="'$(DisableImplicitAssemblyReferences)' != 'true'"
DependsOnTargets="ResolveProjectReferences"
AfterTargets="ResolveTargetingPackAssets">
<ItemGroup>
<_targetingPackReferenceExclusion Include="$(TargetName)" />
<_targetingPackReferenceExclusion Include="@(_ResolvedProjectReferencePaths->'%(Filename)')" />
<_targetingPackReferenceExclusion Include="@(DefaultReferenceExclusion)" />
</ItemGroup>
<ItemGroup>
<_targetingPackReferenceWithExclusion Include="@(Reference)">
<Exclusion>%(_targetingPackReferenceExclusion.Identity)</Exclusion>
</_targetingPackReferenceWithExclusion>
<Reference Remove="@(_targetingPackReferenceWithExclusion)"
Condition="'%(_targetingPackReferenceWithExclusion.ExternallyResolved)' == 'true' and '%(_targetingPackReferenceWithExclusion.Filename)' == '%(_targetingPackReferenceWithExclusion.Exclusion)'" />
</ItemGroup>
</Target>
</Project>
<Project>
<PropertyGroup>
<_WasmTargetsDir Condition="'$(RuntimeSrcDir)' != ''">$(RuntimeSrcDir)\src\mono\wasm\build\</_WasmTargetsDir>
<_WasmTargetsDir Condition="'$(WasmBuildSupportDir)' != ''">$(WasmBuildSupportDir)\wasm\</_WasmTargetsDir>
<EMSDK_PATH Condition="'$(WasmBuildSupportDir)' != ''">$(WasmBuildSupportDir)\emsdk\</EMSDK_PATH>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
<Import Project="$(_WasmTargetsDir)WasmApp.LocalBuild.props" Condition="Exists('$(_WasmTargetsDir)WasmApp.LocalBuild.props')" />
<PropertyGroup>
<WasmBuildAppDependsOn>PrepareForWasmBuild;$(WasmBuildAppDependsOn)</WasmBuildAppDependsOn>
</PropertyGroup>
</Project>
<Project>
<Target Name="CheckWasmLocalBuildInputs" BeforeTargets="Build">
<Error Condition="'$(RuntimeSrcDir)' == '' and '$(WasmBuildSupportDir)' == ''"
Text="Both %24(RuntimeSrcDir) and %24(WasmBuildSupportDir) are not set. Either one of them needs to be set to use local runtime builds" />
<Error Condition="'$(RuntimeSrcDir)' != '' and '$(WasmBuildSupportDir)' != ''"
Text="Both %24(RuntimeSrcDir) and %24(WasmBuildSupportDir) are set. " />
<Error Condition="!Exists('$(_WasmTargetsDir)WasmApp.LocalBuild.props')"
Text="Could not find WasmApp.LocalBuild.props in $(_WasmTargetsDir)" />
<Error Condition="!Exists('$(_WasmTargetsDir)WasmApp.LocalBuild.targets')"
Text="Could not find WasmApp.LocalBuild.targets in $(_WasmTargetsDir)" />
<Warning
Condition="'$(WasmMainJS)' != '' and '$(WasmGenerateAppBundle)' != 'true'"
Text="%24(WasmMainJS) is set when %24(WasmGenerateAppBundle) is not true: it won't be used because an app bundle is not being generated. Possible build authoring error" />
</Target>
<Target Name="PrepareForWasmBuild">
<ItemGroup>
<WasmAssembliesToBundle Include="$(TargetDir)publish\**\*.dll" />
</ItemGroup>
</Target>
<Target Name="PrintRuntimePackPath" BeforeTargets="Build">
<Message Text="** MicrosoftNetCoreAppRuntimePackDir : $(MicrosoftNetCoreAppRuntimePackDir)" Importance="High" />
</Target>
<Import Project="$(_WasmTargetsDir)WasmApp.LocalBuild.targets" Condition="Exists('$(_WasmTargetsDir)WasmApp.LocalBuild.targets')" />
</Project>
#!/usr/bin/env bash
EXECUTION_DIR=$(dirname $0)
cd $EXECUTION_DIR
if [ -z "$HELIX_WORKITEM_UPLOAD_ROOT" ]; then
XHARNESS_OUT="$EXECUTION_DIR/xharness-output"
else
XHARNESS_OUT="$HELIX_WORKITEM_UPLOAD_ROOT/xharness-output"
fi
if [ ! -z "$XHARNESS_CLI_PATH" ]; then
# When running in CI, we only have the .NET runtime available
# We need to call the XHarness CLI DLL directly via dotnet exec
HARNESS_RUNNER="dotnet exec $XHARNESS_CLI_PATH"
else
HARNESS_RUNNER="dotnet xharness"
fi
function set_env_vars()
{
if [ "x$TEST_USING_WORKLOADS" = "xtrue" ]; then
export PATH=$BASE_DIR/dotnet-workload:$PATH
export SDK_FOR_WORKLOAD_TESTING_PATH=$BASE_DIR/dotnet-workload
export AppRefDir=$BASE_DIR/microsoft.netcore.app.ref
elif [ ! -z "$HELIX_WORKITEM_UPLOAD_ROOT" ]; then
export WasmBuildSupportDir=$BASE_DIR/build
fi
}
export TEST_LOG_PATH=${XHARNESS_OUT}/logs
[[RunCommands]]
_exitCode=$?
echo "XHarness artifacts: $XHARNESS_OUT"
exit $_exitCode
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- Don't use any higher level config files. -->
<fallbackPackageFolders>
<clear />
<add key="local" value=".nuget" />
</fallbackPackageFolders>
<packageSources>
<clear />
<add key="dotnet6" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
<disabledPackageSources>
<clear />
</disabledPackageSources>
</configuration>
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="..\resx\*" />
</ItemGroup>
</Project> </Project>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="bye" xml:space="preserve">
<value>ciao</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="hello" xml:space="preserve">
<value>hola</value>
</data>
</root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="bye" xml:space="preserve">
<value>さようなら</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="hello" xml:space="preserve">
<value>こんにちは</value>
</data>
</root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="bye" xml:space="preserve">
<value>bye</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="hello" xml:space="preserve">
<value>hello</value>
</data>
</root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="bye" xml:space="preserve">
<value>ciao</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="hello" xml:space="preserve">
<value>hola</value>
</data>
</root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="bye" xml:space="preserve">
<value>さようなら</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="hello" xml:space="preserve">
<value>こんにちは</value>
</data>
</root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="bye" xml:space="preserve">
<value>bye</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="hello" xml:space="preserve">
<value>hello</value>
</data>
</root>
// 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.Runtime.CompilerServices;
namespace Sample
{
public class Test
{
public static void Main(string[] args)
{
Console.WriteLine ("Hello, World!");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static int TestMeaning()
{
return 42;
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RunAOTCompilation>true</RunAOTCompilation>
<Scenario>WasmTestOnBrowser</Scenario>
<ExpectedExitCode>42</ExpectedExitCode>
<EnableAggressiveTrimming>true</EnableAggressiveTrimming>
<WasmMainJSPath>runtime.js</WasmMainJSPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Content Include="index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Target Name="AfterWasmBuildApp" AfterTargets="WasmBuildApp">
<Copy SourceFiles="$(OutDir)\index.html" DestinationFolder="$(WasmAppDir)" />
</Target>
</Project>
<!DOCTYPE html>
<!-- Licensed to the .NET Foundation under one or more agreements. -->
<!-- The .NET Foundation licenses this file to you under the MIT license. -->
<html>
<head>
<title>TESTS</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body onload="onLoad()">
<h3 id="header">Wasm Browser Sample</h3>
Result from Sample.Test.TestMeaning: <span id="out"></span>
<script type='text/javascript'>
var is_testing = false;
var onLoad = function() {
var url = new URL(decodeURI(window.location));
let args = url.searchParams.getAll('arg');
is_testing = args !== undefined && (args.find(arg => arg == '--testing') !== undefined);
};
var test_exit = function(exit_code)
{
if (!is_testing) {
console.log(`test_exit: ${exit_code}`);
return;
}
/* Set result in a tests_done element, to be read by xharness */
var tests_done_elem = document.createElement("label");
tests_done_elem.id = "tests_done";
tests_done_elem.innerHTML = exit_code.toString();
document.body.appendChild(tests_done_elem);
console.log(`WASM EXIT ${exit_code}`);
};
var App = {
init: function () {
var exit_code = BINDING.call_static_method("[WebAssembly.Browser.AOT.Test] Sample.Test:TestMeaning", []);
document.getElementById("out").innerHTML = exit_code;
if (is_testing)
{
console.debug(`exit_code: ${exit_code}`);
test_exit(exit_code);
}
},
};
</script>
<script type="text/javascript" src="runtime.js"></script>
<script defer src="dotnet.js"></script>
</body>
</html>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
var Module = {
config: null,
preInit: async function() {
await MONO.mono_wasm_load_config("./mono-config.json"); // sets Module.config implicitly
},
onRuntimeInitialized: function () {
if (!Module.config || Module.config.error) {
console.log("No config found");
test_exit(1);
throw(Module.config.error);
}
Module.config.loaded_cb = function () {
try {
App.init ();
} catch (error) {
test_exit(1);
throw (error);
}
};
Module.config.fetch_file_cb = function (asset) {
return fetch (asset, { credentials: 'same-origin' });
}
try
{
MONO.mono_load_runtime_and_bcl_args (Module.config);
} catch (error) {
test_exit(1);
throw(error);
}
},
};
// 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.Runtime.CompilerServices;
namespace Sample
{
public class Test
{
public static void Main(string[] args)
{
Console.WriteLine ("Hello, World!");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static int TestMeaning()
{
return 42;
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<MonoForceInterpreter>true</MonoForceInterpreter>
<RunAOTCompilation>false</RunAOTCompilation>
<TestRuntime>true</TestRuntime>
<Scenario>WasmTestOnBrowser</Scenario>
<ExpectedExitCode>42</ExpectedExitCode>
<WasmMainJSPath>runtime.js</WasmMainJSPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Content Include="index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Target Name="AfterWasmBuildApp" AfterTargets="WasmBuildApp">
<Copy SourceFiles="$(OutDir)\index.html" DestinationFolder="$(WasmAppDir)" />
</Target>
</Project>
<!DOCTYPE html>
<!-- Licensed to the .NET Foundation under one or more agreements. -->
<!-- The .NET Foundation licenses this file to you under the MIT license. -->
<html>
<head>
<title>TESTS</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body onload="onLoad()">
<h3 id="header">Wasm Browser Sample</h3>
Result from Sample.Test.TestMeaning: <span id="out"></span>
<script type='text/javascript'>
var is_testing = false;
var onLoad = function() {
var url = new URL(decodeURI(window.location));
let args = url.searchParams.getAll('arg');
is_testing = args !== undefined && (args.find(arg => arg == '--testing') !== undefined);
};
var test_exit = function(exit_code)
{
if (!is_testing) {
console.log(`test_exit: ${exit_code}`);
return;
}
/* Set result in a tests_done element, to be read by xharness */
var tests_done_elem = document.createElement("label");
tests_done_elem.id = "tests_done";
tests_done_elem.innerHTML = exit_code.toString();
document.body.appendChild(tests_done_elem);
console.log(`WASM EXIT ${exit_code}`);
};
var App = {
init: function () {
var exit_code = BINDING.call_static_method("[WebAssembly.Browser.NormalInterp.Test] Sample.Test:TestMeaning", []);
document.getElementById("out").innerHTML = exit_code;
if (is_testing)
{
console.debug(`exit_code: ${exit_code}`);
test_exit(exit_code);
}
},
};
</script>
<script type="text/javascript" src="runtime.js"></script>
<script defer src="dotnet.js"></script>
</body>
</html>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
var Module = {
config: null,
preInit: async function() {
await MONO.mono_wasm_load_config("./mono-config.json"); // sets Module.config implicitly
},
onRuntimeInitialized: function () {
if (!Module.config || Module.config.error) {
console.log("No config found");
test_exit(1);
throw(Module.config.error);
}
Module.config.loaded_cb = function () {
try {
App.init ();
} catch (error) {
test_exit(1);
throw (error);
}
};
Module.config.fetch_file_cb = function (asset) {
return fetch (asset, { credentials: 'same-origin' });
}
try
{
MONO.mono_load_runtime_and_bcl_args (Module.config);
} catch (error) {
test_exit(1);
throw(error);
}
},
};
// 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.Threading.Tasks;
public class Test
{
public static async Task<int> Main(string[] args)
{
await Task.Delay(1);
Console.WriteLine("Hello Wasm AOT Functional Test!");
return 42;
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RunAOTCompilation>true</RunAOTCompilation>
<TestRuntime>true</TestRuntime>
<ExpectedExitCode>42</ExpectedExitCode>
<EnableAggressiveTrimming>true</EnableAggressiveTrimming>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
</Project>
// 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.Threading.Tasks;
public class Test
{
public static async Task<int> Main(string[] args)
{
await Task.Delay(1);
Console.WriteLine("Hello From Wasm!");
return 42;
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RunAOTCompilation>false</RunAOTCompilation>
<TestRuntime>true</TestRuntime>
<ExpectedExitCode>42</ExpectedExitCode>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
</Project>
// 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.Threading.Tasks;
await Task.Delay(1);
Console.WriteLine("Hello From Wasm!");
return 42;
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RunAOTCompilation>false</RunAOTCompilation>
<TestRuntime>true</TestRuntime>
<ExpectedExitCode>42</ExpectedExitCode>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
</Project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册