diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index a5622bb4c0e..32eb9933b82 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -328,17 +328,29 @@ public void CheckAssemblyCounts ([Values (true, false)] bool isRelease, [Values // DotNet fails, see https://github.com/dotnet/runtime/issues/65484 // Enable the commented out signature (and AOT) once the above is fixed [Test] - public void SmokeTestBuildWithSpecialCharacters ([Values (false, true)] bool forms, [Values (false /*, true*/)] bool aot) + public void SmokeTestBuildWithSpecialCharacters ([Values (false, true)] bool forms, [Values (false, true)] bool aot, [Values] AndroidRuntime runtime) { + if (IgnoreUnsupportedConfiguration (runtime, aot: aot, release: true)) { + return; + } else if (!aot && runtime == AndroidRuntime.NativeAOT) { + // Just saving time, aot && !aot would be identical tests with NativeAOT runtime + Assert.Ignore ("NativeAOT always uses AOT, obviously"); + return; + } + var testName = "テスト"; var rootPath = Path.Combine (Root, "temp", TestName); var proj = forms ? new XamarinFormsAndroidApplicationProject () : new XamarinAndroidApplicationProject (); + proj.SetRuntime (runtime); proj.ProjectName = testName; proj.IsRelease = true; - proj.AotAssemblies = aot; + + if (runtime == AndroidRuntime.MonoVM) { + proj.AotAssemblies = aot; + } using (var builder = CreateApkBuilder (Path.Combine (rootPath, proj.ProjectName))){ Assert.IsTrue (builder.Build (proj), "Build should have succeeded."); @@ -384,8 +396,12 @@ public void CheckWhichRuntimeIsIncluded (string supportedAbi, bool debugSymbols, } [Test] - public void CheckItemMetadata ([Values (true, false)] bool isRelease) + public void CheckItemMetadata ([Values (true, false)] bool isRelease, [Values] AndroidRuntime runtime) { + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, Imports = { @@ -409,11 +425,12 @@ public void CheckItemMetadata ([Values (true, false)] bool isRelease) }, } }; + proj.SetRuntime (runtime); var mainAxml = proj.AndroidResources.First (x => x.Include () == "Resources\\layout\\Main.axml"); mainAxml.MetadataValues = "CustomData=ResourceMetaDataOK"; - using (var builder = CreateApkBuilder (string.Format ("temp/CheckItemMetadata_{0}", isRelease))) { + using (var builder = CreateApkBuilder ()) { builder.Verbosity = LoggerVerbosity.Detailed; builder.Build (proj); StringAssertEx.Contains ("AssetMetaDataOK", builder.LastBuildOutput, "Metadata was not copied for AndroidAsset"); @@ -423,8 +440,12 @@ public void CheckItemMetadata ([Values (true, false)] bool isRelease) // Context https://bugzilla.xamarin.com/show_bug.cgi?id=29706 [Test] - public void CheckLogicalNamePathSeperators ([Values (false, true)] bool isRelease, [Values (false, true)] bool useDesignerAssembly) + public void CheckLogicalNamePathSeperators ([Values (false, true)] bool isRelease, [Values (false, true)] bool useDesignerAssembly, [Values] AndroidRuntime runtime) { + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var illegalSeperator = IsWindows ? "/" : @"\"; var dll = new XamarinAndroidLibraryProject () { ProjectName = "Library1", @@ -436,6 +457,8 @@ public void CheckLogicalNamePathSeperators ([Values (false, true)] bool isReleas }, }, }; + dll.SetRuntime (runtime); + var proj = new XamarinAndroidApplicationProject () { ProjectName = "Application1", IsRelease = isRelease, @@ -449,6 +472,8 @@ public void CheckLogicalNamePathSeperators ([Values (false, true)] bool isReleas new BuildItem ("ProjectReference","..\\Library1\\Library1.csproj"), }, }; + proj.SetRuntime (runtime); + if (!useDesignerAssembly) dll.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); proj.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); @@ -466,11 +491,16 @@ public void CheckLogicalNamePathSeperators ([Values (false, true)] bool isReleas } [Test] - public void ApplicationJavaClassProperties () + public void ApplicationJavaClassProperties ([Values] AndroidRuntime runtime) { + if (IgnoreUnsupportedConfiguration (runtime)) { + return; + } + var proj = new XamarinAndroidApplicationProject (); + proj.SetRuntime (runtime); proj.SetProperty ("AndroidApplicationJavaClass", "android.test.mock.MockApplication"); - var builder = CreateApkBuilder ("temp/ApplicationJavaClassProperties"); + var builder = CreateApkBuilder (); builder.Build (proj); var appsrc = File.ReadAllText (Path.Combine (Root, builder.ProjectDirectory, "obj", "Debug", "android", "AndroidManifest.xml")); Assert.IsTrue (appsrc.Contains ("android.test.mock.MockApplication"), "app class"); @@ -478,11 +508,16 @@ public void ApplicationJavaClassProperties () } [Test] - public void ApplicationIdPlaceholder () + public void ApplicationIdPlaceholder ([Values] AndroidRuntime runtime) { + if (IgnoreUnsupportedConfiguration (runtime)) { + return; + } + var proj = new XamarinAndroidApplicationProject (); + proj.SetRuntime (runtime); proj.AndroidManifest = proj.AndroidManifest.Replace ("", ""); - using (var builder = CreateApkBuilder ("temp/ApplicationIdPlaceholder")) { + using (var builder = CreateApkBuilder ()) { builder.Build (proj); var manifest = XDocument.Load (Path.Combine (Root, builder.ProjectDirectory, "obj", "Debug", "android", "AndroidManifest.xml")); var namespaceResolver = new XmlNamespaceManager (new NameTable ()); @@ -493,13 +528,19 @@ public void ApplicationIdPlaceholder () } [Test] - public void AarContentExtraction () + public void AarContentExtraction ([Values] AndroidRuntime runtime) { + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var aar = new AndroidItem.AndroidAarLibrary ("Jars\\android-crop-1.0.1.aar") { // https://mvnrepository.com/artifact/com.soundcloud.android/android-crop/1.0.1 WebContent = "https://repo1.maven.org/maven2/com/soundcloud/android/android-crop/1.0.1/android-crop-1.0.1.aar" }; var proj = new XamarinAndroidApplicationProject () { + IsRelease = isRelease, OtherBuildItems = { aar, new AndroidItem.AndroidAarLibrary ("fragment-1.2.2.aar") { @@ -507,6 +548,8 @@ public void AarContentExtraction () } }, }; + proj.SetRuntime (runtime); + using (var builder = CreateApkBuilder ()) { Assert.IsTrue (builder.Build (proj), "Build should have succeeded"); var cache = builder.Output.GetIntermediaryPath ("libraryprojectimports.cache"); @@ -557,6 +600,7 @@ public void AarContentExtraction () [TestCaseSource (nameof (GeneratorValidateEventNameArgs))] public void GeneratorValidateEventName (bool failureExpected, bool warningExpected, string metadataFixup, string methodArgs) { + // This test uses the default runtime. It checks generator output, independent on the runtime, so there's no need to repeat it across all the runtimes string java = @" package com.xamarin.testing; @@ -627,6 +671,7 @@ public interface On123Listener [TestCaseSource (nameof (GeneratorValidateMultiMethodEventNameArgs))] public void GeneratorValidateMultiMethodEventName (bool failureExpected, string expectedWarning, string metadataFixup, string methodArgs) { + // This test uses the default runtime. It checks generator output, independent on the runtime, so there's no need to repeat it across all the runtimes string java = @" package com.xamarin.testing; @@ -679,19 +724,28 @@ public interface OnFooListener [Test] [Category ("AOT")] [NonParallelizable] - public void BuildApplicationWithSpacesInPath ([Values (true, false)] bool enableMultiDex, [Values ("", "r8")] string linkTool) + public void BuildApplicationWithSpacesInPath ([Values (true, false)] bool enableMultiDex, [Values ("", "r8")] string linkTool, [Values] AndroidRuntime runtime) { - var folderName = $"BuildReleaseApp AndÜmläüts({enableMultiDex}{linkTool})"; + const bool isRelease = true; + bool aotAssemblies = runtime == AndroidRuntime.MonoVM; + if (IgnoreUnsupportedConfiguration (runtime, aot: aotAssemblies, release: isRelease)) { + return; + } + + var folderName = Path.Combine (Root, "temp", TestName); var lib = new XamarinAndroidLibraryProject { IsRelease = true, ProjectName = "Library1" }; + lib.SetRuntime (runtime); + var proj = new XamarinAndroidApplicationProject () { - IsRelease = true, - AotAssemblies = true, + IsRelease = isRelease, + AotAssemblies = aotAssemblies, LinkTool = linkTool, References = { new BuildItem ("ProjectReference", $"..\\{folderName}Library1\\Library1.csproj") }, }; + proj.SetRuntime (runtime); proj.OtherBuildItems.Add (new BuildItem ("AndroidJavaLibrary", "Hello (World).jar") { BinaryContent = () => Convert.FromBase64String (@" UEsDBBQACAgIAMl8lUsAAAAAAAAAAAAAAAAJAAQATUVUQS1JTkYv/soAAAMAUEsHCAAAAAACAAAAA AAAAFBLAwQUAAgICADJfJVLAAAAAAAAAAAAAAAAFAAAAE1FVEEtSU5GL01BTklGRVNULk1G803My0 @@ -726,7 +780,10 @@ public void BuildApplicationWithSpacesInPath ([Values (true, false)] bool enable Assert.IsTrue (b.Build (proj), "Build should have succeeded."); Assert.IsFalse (b.LastBuildOutput.ContainsText ("Duplicate zip entry"), "Should not get warning about [META-INF/MANIFEST.MF]"); - var className = "Lmono/MonoRuntimeProvider;"; + var className = runtime switch { + AndroidRuntime.NativeAOT => "Lnet/dot/jni/nativeaot/NativeAotRuntimeProvider;", + _ => "Lmono/MonoRuntimeProvider;" + }; var dexFile = b.Output.GetIntermediaryPath (Path.Combine ("android", "bin", "classes.dex")); FileAssert.Exists (dexFile); Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); @@ -736,9 +793,17 @@ public void BuildApplicationWithSpacesInPath ([Values (true, false)] bool enable //This test validates the _CleanIntermediateIfNeeded target [Test] [NonParallelizable] - public void BuildAfterUpgradingNuget () + public void BuildAfterUpgradingNuget ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.MainActivity = proj.DefaultMainActivity.Replace ("public class MainActivity : Activity", "public class MainActivity : AndroidX.AppCompat.App.AppCompatActivity"); proj.PackageReferences.Add (new Package { @@ -785,7 +850,7 @@ public void BuildAfterUpgradingNuget () public void BuildInDesignTimeMode ( [Values (false, true)] bool useManagedParser, - [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR, AndroidRuntime.NativeAOT)] + [Values] AndroidRuntime runtime ) { @@ -803,6 +868,7 @@ AndroidRuntime runtime }, }, }; + lib.SetRuntime (runtime); lib.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", useManagedParser.ToString ()); var proj = new XamarinAndroidApplicationProject () { @@ -848,6 +914,7 @@ AndroidRuntime runtime [Test] public void IfAndroidJarDoesNotExistThrowXA5207 ([Values(true, false)] bool buildingInsideVisualStudio) { + // This test runs on the default runtime, it's testing a runtime-agnostic feature. var path = Path.Combine ("temp", TestName); var AndroidSdkDirectory = CreateFauxAndroidSdkDirectory (Path.Combine (path, "android-sdk"), "24.0.1", new ApiInfo [] { new ApiInfo { Id = "30" } }); var proj = new XamarinAndroidApplicationProject () { @@ -877,6 +944,7 @@ public void IfAndroidJarDoesNotExistThrowXA5207 ([Values(true, false)] bool buil [Test] public void InvalidTargetPlatformVersion ([Values ("android33", "android99.0")] string platformVersion) { + // This test runs on the default runtime, it's testing a runtime-agnostic feature. const string targetFramework = "net9.0"; var project = new XamarinAndroidApplicationProject { TargetFramework = $"{targetFramework}-{platformVersion}", @@ -889,10 +957,17 @@ public void InvalidTargetPlatformVersion ([Values ("android33", "android99.0")] } [Test] - public void XA4212 () + public void XA4212 ([Values] AndroidRuntime runtime) { + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject () { + IsRelease = isRelease, }; + proj.SetRuntime (runtime); proj.Sources.Add (new BuildItem ("Compile", "MyBadJavaObject.cs") { TextContent = () => @" using System; using Android.Runtime; @@ -919,13 +994,18 @@ public void Dispose () } [Test] - public void Desugar ([Values (true, false)] bool isRelease, [Values ("", "r8")] string linkTool) + public void Desugar ([Values (true, false)] bool isRelease, [Values ("", "r8")] string linkTool, [Values] AndroidRuntime runtime) { + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, // desugar is on by default with r8 LinkTool = linkTool, }; + proj.SetRuntime (runtime); //Add a BroadcastReceiver proj.Sources.Add (new BuildItem.Source ("MyReceiver.cs") { @@ -1010,26 +1090,39 @@ public void foo() Assert.IsTrue (builder.Build (proj), "Build should have succeeded"); Assert.IsFalse (builder.LastBuildOutput.ContainsText ("Duplicate zip entry"), "Should not get warning about [META-INF/MANIFEST.MF]"); - var className = "Lmono/MonoRuntimeProvider;"; + var className = runtime switch { + AndroidRuntime.NativeAOT => "Lnet/dot/jni/nativeaot/NativeAotRuntimeProvider;", + _ => "Lmono/MonoRuntimeProvider;" + }; var dexFile = builder.Output.GetIntermediaryPath (Path.Combine ("android", "bin", "classes.dex")); FileAssert.Exists (dexFile); Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); - className = "Lmono/MonoRuntimeProvider_1;"; + className = runtime switch { + AndroidRuntime.NativeAOT => "Lnet/dot/jni/nativeaot/NativeAotRuntimeProvider_1;", + _ => "Lmono/MonoRuntimeProvider_1;" + }; Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); } } //See: https://developer.android.com/about/versions/marshmallow/android-6.0-changes#behavior-apache-http-client [Test] - public void MissingOrgApacheHttpClient () + public void MissingOrgApacheHttpClient ([Values] AndroidRuntime runtime) { + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, Sources = { new BuildItem.Source ("ApacheHttpClient.cs") { BinaryContent = () => ResourceData.ApacheHttpClient_cs, }, }, }; + proj.SetRuntime (runtime); proj.AndroidManifest = proj.AndroidManifest.Replace ("", ""); proj.SetProperty ("AndroidEnableMultiDex", "True"); @@ -1041,10 +1134,15 @@ public void MissingOrgApacheHttpClient () //NOTE: tests type forwarders in Mono.Android.dll to System.Drawing.Common.dll [Test] - public void SystemDrawingCommon () + public void SystemDrawingCommon ([Values] AndroidRuntime runtime) { + const bool isRelease = true; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject { - IsRelease = true, + IsRelease = isRelease, Sources = { new BuildItem.Source ("Foo.cs") { TextContent = () => "class Foo { System.Drawing.Color bar; }" @@ -1054,6 +1152,7 @@ public void SystemDrawingCommon () KnownPackages.Acr_UserDialogs, } }; + proj.SetRuntime (runtime); using (var b = CreateApkBuilder ()) { Assert.IsTrue (b.Build (proj), "Build should have succeeded."); } @@ -1061,14 +1160,21 @@ public void SystemDrawingCommon () //NOTE: Referencing only Microsoft.Extensions.Http, surfaced a bug in [Test] - public void MicrosoftExtensionsHttp () + public void MicrosoftExtensionsHttp ([Values] AndroidRuntime runtime) { + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + // The goal is to create a project with only this var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, PackageReferences = { KnownPackages.Microsoft_Extensions_Http, } }; + proj.SetRuntime (runtime); proj.References.Clear (); proj.Sources.Clear (); // We have to add a custom Target to remove Java.Interop and System.Runtime @@ -1089,13 +1195,18 @@ public void MicrosoftExtensionsHttp () } [Test] - public void FastDeploymentDoesNotAddContentProvider () + public void FastDeploymentDoesNotAddContentProvider ([Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { + if (IgnoreUnsupportedConfiguration (runtime)) { + return; + } + AssertCommercialBuild (); var proj = new XamarinAndroidApplicationProject { EmbedAssembliesIntoApk = false, }; + proj.SetRuntime (runtime); proj.SetProperty ("_XASupportsFastDev", "True"); using (var b = CreateApkBuilder ()) { //NOTE: build will fail, due to $(_XASupportsFastDev) @@ -1113,10 +1224,16 @@ public void FastDeploymentDoesNotAddContentProvider () } [Test] - public void BuildOutsideVisualStudio () + public void BuildOutsideVisualStudio ([Values] AndroidRuntime runtime) { + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var path = Path.Combine ("temp", TestName); var lib = new XamarinAndroidLibraryProject { + IsRelease = isRelease, ProjectName = "Library1", Sources = { new BuildItem.Source ("Foo.cs") { @@ -1124,7 +1241,10 @@ public void BuildOutsideVisualStudio () } }, }; + lib.SetRuntime (runtime); + var proj = new XamarinFormsAndroidApplicationProject { + IsRelease = isRelease, ProjectName = "App1", References = { new BuildItem ("ProjectReference", "..\\Library1\\Library1.csproj") }, Sources = { @@ -1133,6 +1253,8 @@ public void BuildOutsideVisualStudio () } }, }; + proj.SetRuntime (runtime); + using (var libb = CreateDllBuilder (Path.Combine (path, lib.ProjectName))) using (var appb = CreateApkBuilder (Path.Combine (path, proj.ProjectName))) { libb.BuildingInsideVisualStudio = @@ -1145,9 +1267,18 @@ public void BuildOutsideVisualStudio () } [Test] - public void RemoveOldMonoPackageManager () + public void RemoveOldMonoPackageManager ([Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + // TODO: fix the test for NativeAOT. It currently fails on the assertion that MonoPackageManager_Resources.java exists + bool isRelease = false; //runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); using (var b = CreateApkBuilder ()) { b.ThrowOnBuildFailure = false; Assert.IsTrue (b.Build (proj), "Build should have succeeded."); @@ -1185,9 +1316,17 @@ public class ApplicationRegistration { }"); } [Test] - public void CompilerErrorShouldNotRunLinkAssemblies () + public void CompilerErrorShouldNotRunLinkAssemblies ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.Sources.Add (new BuildItem.Source ("SyntaxError.cs") { TextContent = () => "class SyntaxError {" }); @@ -1202,9 +1341,16 @@ public void CompilerErrorShouldNotRunLinkAssemblies () /// This assembly weirdly has no [assembly: System.Runtime.Versioning.TargetFrameworkAttribute()], at all... /// [Test] - public void AssemblyWithMissingTargetFramework () + public void AssemblyWithMissingTargetFramework ([Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { + // TODO: fix the test for NativeAOT. It currently fails on the assertion that CircleImageView.java exists + bool isRelease = false; // runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinFormsAndroidApplicationProject { + IsRelease = isRelease, AndroidResources = { new AndroidItem.AndroidResource ("Resources\\layout\\test.axml") { TextContent = () => @@ -1217,6 +1363,7 @@ public void AssemblyWithMissingTargetFramework () } } }; + proj.SetRuntime (runtime); proj.PackageReferences.Add (KnownPackages.CircleImageView); using (var b = CreateApkBuilder ()) { Assert.IsTrue (b.Build (proj), "build should have succeeded."); @@ -1229,9 +1376,17 @@ public void AssemblyWithMissingTargetFramework () } [Test] - public void WorkManager () + public void WorkManager ([Values] AndroidRuntime runtime) { - var proj = new XamarinFormsAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinFormsAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.Sources.Add (new BuildItem.Source ("MyWorker.cs") { TextContent = () => @"using System; @@ -1254,20 +1409,36 @@ public MyWorker (Context c, WorkerParameters p) : base (c, p) { } } [Test] - public void NuGetizer3000 () + public void NuGetizer3000 ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.PackageReferences.Add (KnownPackages.NuGet_Build_Packaging); - using (var b = CreateApkBuilder (Path.Combine ("temp", nameof (NuGetizer3000)))) { + using (var b = CreateApkBuilder ()) { b.Target = "GetPackageContents"; Assert.IsTrue (b.Build (proj), $"{b.Target} should have succeeded."); } } [Test] - public void NetworkSecurityConfig () + public void NetworkSecurityConfig ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.Sources.Add (new BuildItem ("Compile", "CustomApp.cs") { TextContent = () => @" using System; using Android.App; @@ -1308,12 +1479,21 @@ public CustomApp(IntPtr handle, JniHandleOwnership ownerShip) : base(handle, own } [Test] - public void AbiNameInIntermediateOutputPath () + public void AbiNameInIntermediateOutputPath ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + string config = isRelease ? "Release" : "Debug"; + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.PackageReferences.Add (KnownPackages.Akavache); - proj.OutputPath = Path.Combine ("bin", "x86", "Debug"); - proj.IntermediateOutputPath = Path.Combine ("obj", "x86", "Debug"); + proj.OutputPath = Path.Combine ("bin", "x86", config); + proj.IntermediateOutputPath = Path.Combine ("obj", "x86", config); proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", "var task = Akavache.BlobCache.LocalMachine.GetAllKeys();"); using (var b = CreateApkBuilder ()) { Assert.IsTrue (b.Build (proj), "Build should have succeeded."); @@ -1321,13 +1501,58 @@ public void AbiNameInIntermediateOutputPath () } } + static IEnumerable Get_EnvironmentVariablesData () + { + var ret = new List (); + + foreach (AndroidRuntime runtime in Enum.GetValues (typeof (AndroidRuntime))) { + AddTestData (true, "LowercaseMD5", "", runtime); + AddTestData (true, "LowercaseCrc64", "", runtime); + AddTestData (false, "", "127.0.0.1:9000,suspend,connect", runtime); + } + + return ret; + + void AddTestData (bool useInterpreter, string packageNamingPolicy, string diagnosticConfiguration, AndroidRuntime runtime) + { + ret.Add (new object[] { + useInterpreter, + packageNamingPolicy, + diagnosticConfiguration, + runtime + }); + } + } + [Test] - [TestCase (true, "LowercaseMD5", "")] - [TestCase (true, "LowercaseCrc64", "")] - [TestCase (false, "", "127.0.0.1:9000,suspend,connect")] - public void EnvironmentVariables (bool useInterpreter, string packageNamingPolicy, string diagnosticConfiguration) + [TestCaseSource (nameof (Get_EnvironmentVariablesData))] + public void EnvironmentVariables (bool useInterpreter, string packageNamingPolicy, string diagnosticConfiguration, AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + // NativeAOT supports neither the interpreter nor debug builds, but what we test here is + // environment file creation and contents, and that's relevant to NativeAOT too + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + if (runtime == AndroidRuntime.NativeAOT) { + if (packageNamingPolicy == "LowercaseMD5") { + Assert.Ignore ("NativeAOT does not support the 'LowercaseMD5' package naming policy."); + return; + } + + // TODO: investigate and fix this. For some reason, `DOTNET_MODIFIABLE_ASSEMBLIES=Debug` is not + // in the environment variables file + if (useInterpreter && packageNamingPolicy == "LowercaseCrc64" && diagnosticConfiguration == "") { + Assert.Ignore ("NativeAOT doesn't put the DOTNET_MODIFIABLE_ASSEMBLIES=Debug variable in the environment file."); + return; + } + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.SetProperty ("UseInterpreter", useInterpreter.ToString ()); if (!string.IsNullOrEmpty (packageNamingPolicy)) proj.SetProperty ("AndroidPackageNamingPolicy", packageNamingPolicy); @@ -1349,9 +1574,17 @@ public void EnvironmentVariables (bool useInterpreter, string packageNamingPolic } [Test] - public void KotlinServiceLoader ([Values ("apk", "aab")] string packageFormat) + public void KotlinServiceLoader ([Values ("apk", "aab")] string packageFormat, [Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.SetProperty ("AndroidPackageFormat", packageFormat); if (packageFormat == "aab") // Disable fast deployment for aabs because it is not currently compatible and so gives an XA0119 build error. @@ -1383,9 +1616,17 @@ public void KotlinServiceLoader ([Values ("apk", "aab")] string packageFormat) } [Test] - public void XA1018 () + public void XA1018 ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.SetProperty ("AndroidManifest", "DoesNotExist"); using (var builder = CreateApkBuilder ()) { builder.ThrowOnBuildFailure = false; @@ -1399,13 +1640,20 @@ public void XA1018 () } [Test] - public void XA4313 ([Values ("OpenTK-1.0", "Xamarin.Android.NUnitLite")] string reference) + public void XA4313 ([Values ("OpenTK-1.0", "Xamarin.Android.NUnitLite")] string reference, [Values] AndroidRuntime runtime) { + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject () { + IsRelease = isRelease, References = { new BuildItem.Reference (reference) }, }; + proj.SetRuntime (runtime); using (var builder = CreateApkBuilder ()) { builder.ThrowOnBuildFailure = false; Assert.IsFalse (builder.Build (proj), $"Build should have failed."); @@ -1417,9 +1665,17 @@ public void XA4313 ([Values ("OpenTK-1.0", "Xamarin.Android.NUnitLite")] string } [Test] - public void OpenTKNugetWorks () + public void OpenTKNugetWorks ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.PackageReferences.Add (KnownPackages.Xamarin_Legacy_OpenTK); using (var builder = CreateApkBuilder ()) { builder.ThrowOnBuildFailure = false; @@ -1428,9 +1684,17 @@ public void OpenTKNugetWorks () } [Test] - public void NUnitLiteNugetWorks () + public void NUnitLiteNugetWorks ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.PackageReferences.Add (KnownPackages.Xamarin_Legacy_NUnitLite); using (var builder = CreateApkBuilder ()) { builder.ThrowOnBuildFailure = false; @@ -1438,52 +1702,86 @@ public void NUnitLiteNugetWorks () } } - static readonly object [] XA1027XA1028Source = new object [] { - new object [] { - /* linkTool */ "r8", - /* enableProguard */ null, - /* androidEnableProguard */ "true", - /* expectedBuildResult */ true, - /* expectedWarning */ "0 Warning(s)", - }, - new object [] { - /* linkTool */ "proguard", - /* enableProguard */ null, - /* androidEnableProguard */ "true", - /* expectedBuildResult */ false, - /* expectedWarning */ "0 Warning(s)", - }, - new object [] { - /* linkTool */ null, - /* enableProguard */ null, - /* androidEnableProguard */ null, - /* expectedBuildResult */ true, - /* expectedWarning */ "0 Warning(s)", - }, - new object [] { - /* linkTool */ null, - /* enableProguard */ "true", - /* androidEnableProguard */ null, - /* expectedBuildResult */ false, - /* expectedWarning */ "warning XA1027:", - }, - new object [] { - /* linkTool */ null, - /* enableProguard */ null, - /* androidEnableProguard */ "true", - /* expectedBuildResult */ false, - /* expectedWarning */ "warning XA1028:", + static IEnumerable Get_XA1027XA1028Data () + { + var ret = new List (); + + foreach (AndroidRuntime runtime in Enum.GetValues (typeof (AndroidRuntime))) { + AddTestData ( + linkTool: "r8", + enableProguard: null, + androidEnableProguard: "true", + expectedBuildResult: true, + expectedWarning: "0 Warning(s)", + runtime + ); + + AddTestData ( + linkTool: "proguard", + enableProguard: null, + androidEnableProguard: "true", + expectedBuildResult: false, + expectedWarning: "0 Warning(s)", + runtime + ); + + AddTestData ( + linkTool: null, + enableProguard: null, + androidEnableProguard: null, + expectedBuildResult: true, + expectedWarning: "0 Warning(s)", + runtime + ); + + AddTestData ( + linkTool: null, + enableProguard: "true", + androidEnableProguard: null, + expectedBuildResult: false, + expectedWarning: "warning XA1027:", + runtime + ); + + AddTestData ( + linkTool: null, + enableProguard: null, + androidEnableProguard: "true", + expectedBuildResult: false, + expectedWarning: "warning XA1028:", + runtime + ); } - }; + + return ret; + + void AddTestData (string linkTool, string enableProguard, string androidEnableProguard, bool expectedBuildResult, string expectedWarning, AndroidRuntime runtime) + { + ret.Add (new object[] { + linkTool, + enableProguard, + androidEnableProguard, + expectedBuildResult, + expectedWarning, + runtime + }); + } + } [Test] - [TestCaseSource (nameof (XA1027XA1028Source))] - public void XA1027XA1028 (string linkTool, string enableProguard, string androidEnableProguard, bool expectedBuildResult, string expectedWarning) + [TestCaseSource (nameof (Get_XA1027XA1028Data))] + public void XA1027XA1028 (string linkTool, string enableProguard, string androidEnableProguard, bool expectedBuildResult, string expectedWarning, AndroidRuntime runtime) { + const bool isRelease = true; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject { LinkTool = linkTool, - IsRelease = true + IsRelease = isRelease, }; + proj.SetRuntime (runtime); proj.SetProperty ("EnableProguard", enableProguard); proj.SetProperty ("AndroidEnableProguard", androidEnableProguard); using (var builder = CreateApkBuilder ()) { @@ -1499,11 +1797,17 @@ public void XA1027XA1028 (string linkTool, string enableProguard, string android } [Test] - public void XA4310 ([Values ("apk", "aab")] string packageFormat) + public void XA4310 ([Values ("apk", "aab")] string packageFormat, [Values] AndroidRuntime runtime) { + const bool isRelease = true; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject { - IsRelease = true, + IsRelease = isRelease, }; + proj.SetRuntime (runtime); proj.SetProperty ("AndroidKeyStore", "true"); proj.SetProperty ("AndroidSigningKeyStore", "DoesNotExist"); proj.SetProperty ("AndroidSigningStorePass", "android"); @@ -1516,17 +1820,39 @@ public void XA4310 ([Values ("apk", "aab")] string packageFormat) StringAssertEx.Contains ("error XA4310", builder.LastBuildOutput, "Error should be XA4310"); StringAssertEx.Contains ("`DoesNotExist`", builder.LastBuildOutput, "Error should include the name of the nonexistent file"); - builder.AssertHasNoWarnings (); + + if (runtime != AndroidRuntime.NativeAOT) { + builder.AssertHasNoWarnings (); + return; + } + + // NativeAOT currently (Nov 2025) produces the following warning + // warning IL3053: Assembly 'Mono.Android' produced AOT analysis warnings. + string expectedWarning = "warning IL3053:"; + Assert.IsNotNull ( + builder.LastBuildOutput + .SkipWhile (x => !x.StartsWith ("Build FAILED.", StringComparison.Ordinal)) + .FirstOrDefault (x => x.Contains (expectedWarning)), + $"Build output should contain '{expectedWarning}'." + ); } } [Test] [NonParallelizable] - public void CheckLintErrorsAndWarnings () + public void CheckLintErrorsAndWarnings ([Values] AndroidRuntime runtime) { string disabledIssues = "StaticFieldLeak,ObsoleteSdkInt,AllowBackup,ExportedReceiver,RedundantLabel,AppLinkWarning"; - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.SetProperty ("AndroidLintEnabled", true.ToString ()); proj.SetProperty ("AndroidLintDisabledIssues", disabledIssues); proj.SetProperty ("AndroidLintEnabledIssues", ""); @@ -1553,7 +1879,7 @@ public class MainActivity : Activity "; } }); - using (var b = CreateApkBuilder ("temp/CheckLintErrorsAndWarnings", cleanupOnDispose: false)) { + using (var b = CreateApkBuilder ()) { var maxApiLevel = AndroidSdkResolver.GetMaxInstalledPlatform (); b.LatestTargetFrameworkVersion (out string apiLevel); if (AndroidSdkResolver.TryParseAndroidSdkVersion (apiLevel, out var v) && v < maxApiLevel) { @@ -1570,9 +1896,17 @@ public class MainActivity : Activity } [Test] - public void CheckLintConfigMerging () + public void CheckLintConfigMerging ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.SetProperty ("AndroidLintEnabled", true.ToString ()); proj.OtherBuildItems.Add (new AndroidItem.AndroidLintConfig ("lint1.xml") { TextContent = () => @" @@ -1586,9 +1920,9 @@ public void CheckLintConfigMerging () " }); - using (var b = CreateApkBuilder ("temp/CheckLintConfigMerging", false, false)) { + using (var b = CreateApkBuilder ()) { Assert.IsTrue (b.Build (proj), "Build should have succeeded."); - var lintFile = Path.Combine (Root, "temp", "CheckLintConfigMerging", proj.IntermediateOutputPath, "lint.xml"); + var lintFile = Path.Combine (Root, "temp", TestName, proj.IntermediateOutputPath, "lint.xml"); Assert.IsTrue (File.Exists (lintFile), "{0} should have been created.", lintFile); var doc = XDocument.Load (lintFile); Assert.IsNotNull (doc, "Document should have loaded successfully."); @@ -1605,8 +1939,12 @@ public void CheckLintConfigMerging () } [Test] - public void BuildApplicationWithJavaSourceUsingAndroidX ([Values(true, false)] bool isRelease) + public void BuildApplicationWithJavaSourceUsingAndroidX ([Values(true, false)] bool isRelease, [Values] AndroidRuntime runtime) { + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, AndroidJavaSources = { @@ -1624,6 +1962,7 @@ public static Toolbar GetToolbar (Context context) { }, } }; + proj.SetRuntime (runtime); proj.PackageReferences.Add (KnownPackages.AndroidXAppCompat); using (var b = CreateApkBuilder ()) { b.ThrowOnBuildFailure = false; @@ -1634,9 +1973,17 @@ public static Toolbar GetToolbar (Context context) { } [Test] - public void BuildApplicationCheckThatAddStaticResourcesTargetDoesNotRerun () + public void BuildApplicationCheckThatAddStaticResourcesTargetDoesNotRerun ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject () { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); using (var b = CreateApkBuilder ()) { b.ThrowOnBuildFailure = false; Assert.IsTrue (b.Build (proj), "Build should not have failed"); @@ -1651,9 +1998,17 @@ public void BuildApplicationCheckThatAddStaticResourcesTargetDoesNotRerun () } [Test] - public void CheckJavaError () + public void CheckJavaError ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject () { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.AndroidJavaSources.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "TestMe.java") { TextContent = () => "public classo TestMe { }", Encoding = Encoding.ASCII @@ -1664,7 +2019,7 @@ public void CheckJavaError () "}", Encoding = Encoding.ASCII }); - using (var b = CreateApkBuilder ("temp/CheckJavaError")) { + using (var b = CreateApkBuilder ()) { b.ThrowOnBuildFailure = false; Assert.IsFalse (b.Build (proj), "Build should have failed."); var ext = b.IsUnix ? "" : ".exe"; @@ -1681,9 +2036,17 @@ public void CheckJavaError () /// Based on issue raised in /// https://bugzilla.xamarin.com/show_bug.cgi?id=28721 /// - public void DuplicateValuesInResourceCaseMap () + public void DuplicateValuesInResourceCaseMap ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject () { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.AndroidResources.Add (new AndroidItem.AndroidResource ("Resources\\layout\\test.axml") { TextContent = () => { return "\n"; @@ -1703,9 +2066,17 @@ public void DuplicateValuesInResourceCaseMap () } [Test] - public void CheckLintResourceFileReferencesAreFixed () + public void CheckLintResourceFileReferencesAreFixed ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (); + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject () { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.SetProperty ("AndroidLintEnabled", true.ToString ()); proj.AndroidResources.Add (new AndroidItem.AndroidResource ("Resources\\layout\\test.axml") { TextContent = () => { @@ -1775,9 +2146,15 @@ public void SimilarAndroidXAssemblyNames (bool publishTrimmed, AndroidRuntime ru } [Test] - public void IncrementalBuildDifferentDevice() + public void IncrementalBuildDifferentDevice ([Values] AndroidRuntime runtime) { + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, Imports = { new Import (() => "MockPrimaryCpuAbi.targets") { TextContent = () => @@ -1796,6 +2173,7 @@ public void IncrementalBuildDifferentDevice() }, }, }; + proj.SetRuntime (runtime); using var builder = CreateApkBuilder (); builder.Target = "Build"; builder.BuildingInsideVisualStudio = false; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs index 4dffeaa58c6..f8f78db81f5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs @@ -564,6 +564,32 @@ protected bool RunCommand (string command, string arguments) } } + protected bool IgnoreUnsupportedConfiguration (AndroidRuntime runtime, bool aot = false, bool release = false) + { + if (runtime == AndroidRuntime.NativeAOT) { + // NativeAOT is release-only, AOT is always implied + if (release) { + return false; + } + + Assert.Ignore ($"NativeAOT: unsupported configuration (release == {release})"); + return true; + } + + if (runtime == AndroidRuntime.CoreCLR) { + // CoreCLR doesn't support AOT + if (!aot) { + return false; + } + + Assert.Ignore ($"CoreCLR: unsupported configuration (aot == {aot})"); + return true; + } + + // MonoVM supports all the combinations + return false; + } + [SetUp] public void TestSetup () { diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ProjectExtensions.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ProjectExtensions.cs index aacf34be9b1..a3cac4affef 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ProjectExtensions.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ProjectExtensions.cs @@ -1,3 +1,5 @@ +using System; + using Xamarin.Android.Tasks; using Xamarin.ProjectTools; @@ -10,6 +12,31 @@ public static class ProjectExtensions /// NOTE: $(EnablePreviewFeatures) ignores warning XA1040: The NativeAOT runtime on Android is an experimental feature and not yet suitable for production use. /// public static void SetRuntime (this XamarinProject project, AndroidRuntime runtime) + { + DoSetRuntime (project, runtime); + EnablePreviewFeaturesIfNeeded (project, runtime); + } + + public static void SetRuntime (this XamarinAndroidApplicationProject project, AndroidRuntime runtime) + { + if (runtime != AndroidRuntime.NativeAOT) { + DoSetRuntime (project, runtime); + return; + } + project.SetPublishAot (true, BaseTest.AndroidNdkPath); + EnablePreviewFeaturesIfNeeded (project, runtime); + } + + static void EnablePreviewFeaturesIfNeeded (XamarinProject project, AndroidRuntime runtime) + { + if (runtime != AndroidRuntime.NativeAOT) { + return; + } + + project.SetProperty ("EnablePreviewFeatures", "true"); + } + + static void DoSetRuntime (XamarinProject project, AndroidRuntime runtime) { switch (runtime) { case AndroidRuntime.CoreCLR: @@ -17,11 +44,13 @@ public static void SetRuntime (this XamarinProject project, AndroidRuntime runti break; case AndroidRuntime.NativeAOT: project.SetProperty ("PublishAot", "true"); - project.SetProperty ("EnablePreviewFeatures", "true"); break; - default: + case AndroidRuntime.MonoVM: project.SetProperty ("UseMonoRuntime", "true"); break; + + default: + throw new NotSupportedException ($"Unsupported runtime {runtime}"); } } }