From bca804d1796d4d95ac1fb13a55e5636806b17223 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 8 Dec 2025 13:37:56 +0100 Subject: [PATCH 1/8] Introduce a package naming helper On-device tests which run the same project but with different runtimes must use different package names or we might find ourselves in a situation when an application built for a different runtime and installed over a previous version which uses another runtime, won't even start. This happened with NativeAOT in the InstallAndRunTests.DotNetRun test. --- .../Utilities/PackageUtils.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/PackageUtils.cs diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/PackageUtils.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/PackageUtils.cs new file mode 100644 index 00000000000..c9e3e85bb29 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/PackageUtils.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.CompilerServices; +using System.Text; +using Xamarin.Android.Tasks; +using Xamarin.ProjectTools; + +namespace Xamarin.Android.Build.Tests; + +class PackageUtils +{ + /// + /// Constructs Android package name parameter for the which includes + /// the runtime used to build and run the application. A unique per-runtime package name is necessary so that elements + /// of different runtimes don't mix when running the same test for several of them. + /// + public static string MakePackageName (AndroidRuntime runtime, [CallerMemberName] string packageName = "") + { + if (String.IsNullOrEmpty (packageName)) { + throw new ArgumentException ("Must not be null or empty", nameof (packageName)); + } + + var sb = new StringBuilder (packageName); + sb.Append ('_'); + sb.Append (runtime.ToString ().ToLowerInvariant ()); + + return sb.ToString (); + } +} From f681791cf8917631437828318c35999be77b59b8 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 11 Dec 2025 15:06:18 +0100 Subject: [PATCH 2/8] LocalizationTests updated --- .../Tests/LocalizationTests.cs | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/LocalizationTests.cs b/tests/MSBuildDeviceIntegration/Tests/LocalizationTests.cs index 647bfee8024..8a4c50accfe 100644 --- a/tests/MSBuildDeviceIntegration/Tests/LocalizationTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/LocalizationTests.cs @@ -9,10 +9,12 @@ using NUnit.Framework.Interfaces; using Xamarin.ProjectTools; using Humanizer; +using Xamarin.Android.Tasks; namespace Xamarin.Android.Build.Tests { [TestFixture] + [TestFixtureSource (nameof (Get_Fixture_Args))] [Category ("Localization")] [NonParallelizable] public class LocalizationTests : DeviceTest @@ -20,6 +22,25 @@ public class LocalizationTests : DeviceTest ProjectBuilder builder; XamarinAndroidApplicationProject proj; string localeFileSuffix; + readonly AndroidRuntime runtime; + readonly bool isRelease; + + static IEnumerable Get_Fixture_Args () + { + var ret = new List (); + + foreach (AndroidRuntime runtime in Enum.GetValues (typeof (AndroidRuntime))) { + ret.Add (new object[] { runtime }); + } + + return ret; + } + + public LocalizationTests (AndroidRuntime runtime) + { + this.runtime = runtime; + isRelease = runtime == AndroidRuntime.NativeAOT; + } [OneTimeSetUp] public void BeforeAllTests () @@ -31,7 +52,11 @@ public void BeforeAllTests () Assert.Fail ("LocalizationTests need to use `su root` and this device does not support that feature. Try using an emulator."); } - proj = new XamarinAndroidApplicationProject (packageName: "LocalizationTests"); + proj = new XamarinAndroidApplicationProject (packageName: PackageUtils.MakePackageName (runtime, "LocalizationTests")) { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); + proj.PackageReferences.Add (new Package { Id = "Humanizer", Version = "2.14.1", @@ -49,7 +74,7 @@ public void BeforeAllTests () InlineData.AddCultureResourcesToProject (proj, "Strings", "SomeString"); InlineData.AddCultureResourceDesignerToProject (proj, proj.RootNamespace ?? proj.ProjectName, "Strings", "SomeString"); - builder = CreateApkBuilder (Path.Combine ("temp", "LocalizationTests")); + builder = CreateApkBuilder (Path.Combine ("temp", TestName)); builder.BuildLogFile = "onetimesetup-install.log"; Assert.IsTrue (builder.Install (proj), "Install should have succeeded."); } From fffd30daf7b1159659dbefcb0848d14ce562a60a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 11 Dec 2025 15:22:32 +0100 Subject: [PATCH 3/8] MarshalMethodsGCHangTests.MarshalMethodsAppRuns updated --- .../Tests/MarshalMethodsGCHangTests.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/MarshalMethodsGCHangTests.cs b/tests/MSBuildDeviceIntegration/Tests/MarshalMethodsGCHangTests.cs index 0c251920517..42e8e384ab2 100644 --- a/tests/MSBuildDeviceIntegration/Tests/MarshalMethodsGCHangTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/MarshalMethodsGCHangTests.cs @@ -84,12 +84,21 @@ public override void Close () "; [Test] - public void MarshalMethodsAppRuns ([Values (AndroidRuntime.CoreCLR, AndroidRuntime.MonoVM)] AndroidRuntime runtime) + public void MarshalMethodsAppRuns ([Values] AndroidRuntime runtime) { - var proj = new XamarinAndroidApplicationProject (packageName: "marshal2") { - IsRelease = true, + const bool isRelease = true; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + if (runtime == AndroidRuntime.NativeAOT) { + Assert.Ignore ("Not supported with NativeAOT"); + } + + var proj = new XamarinAndroidApplicationProject (packageName: PackageUtils.MakePackageName (runtime, "marshal2")) { + IsRelease = isRelease, EnableMarshalMethods = true, - SupportedOSPlatformVersion = "23", + SupportedOSPlatformVersion = "24", // Minimum 24 to be able to test on Android 16 TrimModeRelease = TrimMode.Full, ProjectName = "marshal2", }; From ca05b6b651346ef95a62eda945966e22992e639e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 11 Dec 2025 15:24:08 +0100 Subject: [PATCH 4/8] MonoAndroidExportTest.MonoAndroidExportReferencedAppStarts updated --- .../Tests/MonoAndroidExportTest.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/MonoAndroidExportTest.cs b/tests/MSBuildDeviceIntegration/Tests/MonoAndroidExportTest.cs index 6a0f1364dfe..a63f3fdea3e 100644 --- a/tests/MSBuildDeviceIntegration/Tests/MonoAndroidExportTest.cs +++ b/tests/MSBuildDeviceIntegration/Tests/MonoAndroidExportTest.cs @@ -18,12 +18,16 @@ public class MonoAndroidExportTest : DeviceTest { [Test] public void MonoAndroidExportReferencedAppStarts ( - [Values (true, false)] bool embedAssemblies, - [Values (true, false)] bool isRelease, - [Values (AndroidRuntime.CoreCLR, AndroidRuntime.MonoVM)] AndroidRuntime runtime) + [Values] bool embedAssemblies, + [Values] bool isRelease, + [Values] AndroidRuntime runtime) { + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + AssertCommercialBuild (); - var proj = new XamarinAndroidApplicationProject () { + var proj = new XamarinAndroidApplicationProject (packageName: PackageUtils.MakePackageName (runtime)) { IsRelease = isRelease, References = { new BuildItem.Reference ("Mono.Android.Export"), From c6360d31e760c703b8caa7d7dd94d698889b78e4 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 11 Dec 2025 15:27:35 +0100 Subject: [PATCH 5/8] PerformanceTest, leave for later --- tests/MSBuildDeviceIntegration/Tests/PerformanceTest.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/PerformanceTest.cs b/tests/MSBuildDeviceIntegration/Tests/PerformanceTest.cs index 2240e29b153..58e7875477b 100644 --- a/tests/MSBuildDeviceIntegration/Tests/PerformanceTest.cs +++ b/tests/MSBuildDeviceIntegration/Tests/PerformanceTest.cs @@ -6,10 +6,12 @@ using Microsoft.Build.Framework; using Microsoft.Build.Logging.StructuredLogger; using NUnit.Framework; +using Xamarin.Android.Tasks; using Xamarin.ProjectTools; namespace Xamarin.Android.Build.Tests { + // TODO: update for NativeAOT and CoreCLR [TestFixture] [Category ("Performance")] public class PerformanceTest : DeviceTest @@ -61,7 +63,7 @@ void Profile (ProjectBuilder builder, int iterations, Action act action (builder); var actual = GetDurationFromBinLog (builder); TestContext.Out.WriteLine ($"run {i} took: {actual}ms"); - total += actual; + total += actual; if (afterRun is not null) afterRun (builder); } From 54c29252bd493b4990cda5fb1cd8b3888a27e6ea Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 11 Dec 2025 15:37:17 +0100 Subject: [PATCH 6/8] SystemApplicationTests.SystemApplicationCanInstall updated --- .../Tests/SystemApplicationTests.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/SystemApplicationTests.cs b/tests/MSBuildDeviceIntegration/Tests/SystemApplicationTests.cs index 39ac45ea482..acde868e409 100644 --- a/tests/MSBuildDeviceIntegration/Tests/SystemApplicationTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/SystemApplicationTests.cs @@ -7,6 +7,7 @@ using System.Text; using System.Xml.Linq; using System.Collections.Generic; +using Xamarin.Android.Tasks; namespace Xamarin.Android.Build.Tests { @@ -16,14 +17,19 @@ public class SystemApplicationTests : DeviceTest { // All Tests here require the emulator to be started with -writable-system [Test, Category ("SystemApplication")] - public void SystemApplicationCanInstall () + public void SystemApplicationCanInstall ([Values] AndroidRuntime runtime) { + const bool isRelease = false; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } AssertCommercialBuild (); - var proj = new XamarinAndroidApplicationProject () { + var proj = new XamarinAndroidApplicationProject (packageName: PackageUtils.MakePackageName (runtime)) { IsRelease = false, EmbedAssembliesIntoApk = false, }; + proj.SetRuntime (runtime); proj.OtherBuildItems.Add (new BuildItem ("None", "platform.pk8") { WebContent = "https://github.com/aosp-mirror/platform_build/raw/master/target/product/security/platform.pk8" }); From 956ed60c41c9c21f38a8c0efde4c93c73fc28047 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 11 Dec 2025 15:43:16 +0100 Subject: [PATCH 7/8] TimeZoneInfoTests updated --- .../Tests/TimeZoneInfoTests.cs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/TimeZoneInfoTests.cs b/tests/MSBuildDeviceIntegration/Tests/TimeZoneInfoTests.cs index d4e6033a063..ac934888791 100644 --- a/tests/MSBuildDeviceIntegration/Tests/TimeZoneInfoTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/TimeZoneInfoTests.cs @@ -5,6 +5,7 @@ using System.Threading; using NUnit.Framework; using NUnit.Framework.Interfaces; +using Xamarin.Android.Tasks; using Xamarin.ProjectTools; namespace Xamarin.Android.Build.Tests @@ -17,6 +18,25 @@ public class TimeZoneInfoTests : DeviceTest ProjectBuilder builder; XamarinAndroidApplicationProject proj; string tzFileSuffix; + readonly AndroidRuntime runtime; + readonly bool isRelease; + + static IEnumerable Get_Fixture_Args () + { + var ret = new List (); + + foreach (AndroidRuntime runtime in Enum.GetValues (typeof (AndroidRuntime))) { + ret.Add (new object[] { runtime }); + } + + return ret; + } + + public TimeZoneInfoTests (AndroidRuntime runtime) + { + this.runtime = runtime; + isRelease = runtime == AndroidRuntime.NativeAOT; + } [OneTimeSetUp] public void BeforeAllTests () @@ -30,13 +50,16 @@ public void BeforeAllTests () // Disable auto timezone RunAdbCommand ("shell settings put global auto_time_zone 0"); - proj = new XamarinAndroidApplicationProject (packageName: "TimeZoneInfoTests"); + proj = new XamarinAndroidApplicationProject (packageName: PackageUtils.MakePackageName (runtime, "TimeZoneInfoTests")) { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", @"button.Text = $""TimeZoneInfo={TimeZoneInfo.Local.Id}""; Console.WriteLine ($""TimeZoneInfoNative={Java.Util.TimeZone.Default.ID}""); Console.WriteLine ($""TimeZoneInfoTests.TimeZoneInfo={TimeZoneInfo.Local.Id}""); "); - builder = CreateApkBuilder (Path.Combine ("temp", "TimeZoneInfoTests")); + builder = CreateApkBuilder (Path.Combine ("temp", TestName)); builder.BuildLogFile = "onetimesetup-install.log"; Assert.IsTrue (builder.Install (proj), "Install should have succeeded."); } From 834ad6052021fce6b51c9de94d4a76f5fff6948f Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 11 Dec 2025 15:50:58 +0100 Subject: [PATCH 8/8] UncaughtExceptionTests.EnsureUncaughtExceptionWorks works --- .../Tests/UncaughtExceptionTests.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/UncaughtExceptionTests.cs b/tests/MSBuildDeviceIntegration/Tests/UncaughtExceptionTests.cs index 50a6425c5be..8b56eb48056 100644 --- a/tests/MSBuildDeviceIntegration/Tests/UncaughtExceptionTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/UncaughtExceptionTests.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text.RegularExpressions; using NUnit.Framework; +using Xamarin.Android.Tasks; using Xamarin.ProjectTools; namespace Xamarin.Android.Build.Tests @@ -20,12 +21,18 @@ class LogcatLine }; [Test] - public void EnsureUncaughtExceptionWorks () + public void EnsureUncaughtExceptionWorks ([Values] AndroidRuntime runtime) { + bool isRelease = runtime == AndroidRuntime.NativeAOT; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + var lib = new XamarinAndroidBindingProject { ProjectName = "Scratch.Try", AndroidClassParser = "class-parse", }; + lib.SetRuntime (runtime); lib.Imports.Add ( new Import (() => "Directory.Build.targets") { @@ -89,9 +96,11 @@ public static final void tryCatchFinally (Runnable r, CatchThrowableHandler c, R " }); - var app = new XamarinAndroidApplicationProject { + var app = new XamarinAndroidApplicationProject (packageName: PackageUtils.MakePackageName (runtime)) { + IsRelease = isRelease, ProjectName = "Scratch.JMJMException", }; + app.SetRuntime (runtime); app.SetDefaultTargetDevice (); app.AddReference (lib);