From de10fd32fb6f547450d7d88b58c32a5323ccdfd2 Mon Sep 17 00:00:00 2001 From: Peter Collins Date: Thu, 9 Mar 2023 17:25:56 -0500 Subject: [PATCH] [tests] Stop using XASdkProject Replaces all instances of `XASdkProject` with `XamarinProject` types to unify test project generation across all MSBuild suites. --- .../CodeBehindTests.cs | 3 +- .../Xamarin.Android.Build.Tests/XASdkTests.cs | 375 +++++++++--------- .../Android/XASdkProject.cs | 116 ------ .../Android/XamarinFormsXASdkProject.cs | 91 ----- .../Xamarin.ProjectTools/Common/DotNetCLI.cs | 16 +- .../Common/DotNetStandard.cs | 14 - .../Common/XamarinProject.cs | 41 +- .../Utilities/ProjectExtensions.cs | 4 +- .../Utilities/XmlUtils.cs | 6 +- .../Tests/InstallAndRunTests.cs | 41 +- .../Tests/XASdkDeployTests.cs | 117 ++---- 11 files changed, 278 insertions(+), 546 deletions(-) delete mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs delete mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinFormsXASdkProject.cs diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs index 4ee93538017..c47c0a169ee 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/CodeBehindTests.cs @@ -694,7 +694,8 @@ string PrepareProject (string testName) CopyRecursively (TestProjectRootDirectory, temporaryProjectPath, ignore); CopyRecursively (CommonSampleLibraryRootDirectory, Path.Combine (tempRoot, CommonSampleLibraryName), ignore); CopyFile (Path.Combine (XABuildPaths.TopDirectory, "Directory.Build.props"), Path.Combine (tempRoot, "Directory.Build.props" )); - XASdkProject.SaveNuGetConfig (tempRoot); + var project = new XamarinAndroidApplicationProject (); + project.CopyNuGetConfig (Path.Combine (tempRoot, "NuGet.config")); return temporaryProjectPath; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs index 9ba397c83ae..0839f12ed61 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs @@ -16,15 +16,11 @@ #if !NET472 namespace Xamarin.Android.Build.Tests { + [Obsolete ("De-dupe and migrate these tests to Build, Package, or other test fixtures.")] [TestFixture] [NonParallelizable] // On MacOS, parallel /restore causes issues public class XASdkTests : BaseTest { - /// - /// The full path to the project directory - /// - public string FullProjectDirectory { get; set; } - static readonly object [] DotNetBuildLibrarySource = new object [] { new object [] { /* isRelease */ false, @@ -68,9 +64,10 @@ public void DotNetBuildLibrary (bool isRelease, bool duplicateAar, bool useDesig // Setup dependencies App A -> Lib B -> Lib C - var libC = new XASdkProject (outputType: "Library") { + var libC = new XamarinAndroidLibraryProject { ProjectName = "LibraryC", IsRelease = isRelease, + EnableDefaultItems = true, Sources = { new BuildItem.Source ("Bar.cs") { TextContent = () => "public class Bar { }", @@ -90,19 +87,20 @@ public void DotNetBuildLibrary (bool isRelease, bool duplicateAar, bool useDesig var activity = libC.Sources.FirstOrDefault (s => s.Include () == "MainActivity.cs"); if (activity != null) libC.Sources.Remove (activity); - var libCBuilder = CreateDotNetBuilder (libC, Path.Combine (path, libC.ProjectName)); - Assert.IsTrue (libCBuilder.Build (), $"{libC.ProjectName} should succeed"); + var libCBuilder = CreateDllBuilder (Path.Combine ("temp", libC.ProjectName)); + Assert.IsTrue (libCBuilder.Build (libC), $"{libC.ProjectName} should succeed"); - var aarPath = Path.Combine (FullProjectDirectory, libC.OutputPath, $"{libC.ProjectName}.aar"); + var aarPath = Path.Combine (Root, libCBuilder.ProjectDirectory, libC.OutputPath, $"{libC.ProjectName}.aar"); FileAssert.Exists (aarPath); using (var aar = ZipHelper.OpenZip (aarPath)) { aar.AssertContainsEntry (aarPath, "assets/bar/bar.txt"); aar.AssertEntryEquals (aarPath, "proguard.txt", "# LibraryC"); } - var libB = new XASdkProject (outputType: "Library") { + var libB = new XamarinAndroidLibraryProject { ProjectName = "LibraryB", IsRelease = isRelease, + EnableDefaultItems = true, Sources = { new BuildItem.Source ("Foo.cs") { TextContent = () => @@ -163,14 +161,14 @@ public Foo () activity = libB.Sources.FirstOrDefault (s => s.Include () == "MainActivity.cs"); if (activity != null) libB.Sources.Remove (activity); - var libBBuilder = CreateDotNetBuilder (libB, Path.Combine (path, libB.ProjectName)); - Assert.IsTrue (libBBuilder.Build (), $"{libB.ProjectName} should succeed"); + var libBBuilder = CreateDllBuilder (Path.Combine ("temp", libB.ProjectName)); + Assert.IsTrue (libBBuilder.Build (libB), $"{libB.ProjectName} should succeed"); var projectJarHash = Files.HashString (Path.Combine (libB.IntermediateOutputPath, "binding", "bin", $"{libB.ProjectName}.jar").Replace ("\\", "/")); // Check .aar file for class library - var libBOutputPath = Path.Combine (FullProjectDirectory, libB.OutputPath); + var libBOutputPath = Path.Combine (Root, libBBuilder.ProjectDirectory, libB.OutputPath); aarPath = Path.Combine (libBOutputPath, $"{libB.ProjectName}.aar"); FileAssert.Exists (aarPath); FileAssert.Exists (Path.Combine (libBOutputPath, "bar.aar")); @@ -190,15 +188,16 @@ public Foo () } // Check EmbeddedResource files do not exist - var assemblyPath = Path.Combine (FullProjectDirectory, libB.OutputPath, $"{libB.ProjectName}.dll"); + var assemblyPath = Path.Combine (Root, libBBuilder.ProjectDirectory, libB.OutputPath, $"{libB.ProjectName}.dll"); FileAssert.Exists (assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath)) { Assert.AreEqual (0, assembly.MainModule.Resources.Count); } - var appA = new XASdkProject { + var appA = new XamarinAndroidApplicationProject { ProjectName = "AppA", IsRelease = isRelease, + EnableDefaultItems = true, Sources = { new BuildItem.Source ("Bar.cs") { TextContent = () => "public class Bar : Foo { }", @@ -211,11 +210,11 @@ public Foo () appA.OtherBuildItems.Add (new AndroidItem.AndroidLibrary (aarPath)); } appA.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); - var appBuilder = CreateDotNetBuilder (appA, Path.Combine (path, appA.ProjectName)); - Assert.IsTrue (appBuilder.Build (), $"{appA.ProjectName} should succeed"); + var appBuilder = CreateApkBuilder (Path.Combine ("temp", appA.ProjectName)); + Assert.IsTrue (appBuilder.Build (appA), $"{appA.ProjectName} should succeed"); // Check .apk/.aab for assets, res, and native libraries - var apkPath = Path.Combine (FullProjectDirectory, appA.OutputPath, $"{appA.PackageName}-Signed.apk"); + var apkPath = Path.Combine (Root, appBuilder.ProjectDirectory, appA.OutputPath, $"{appA.PackageName}-Signed.apk"); FileAssert.Exists (apkPath); using (var apk = ZipHelper.OpenZip (apkPath)) { apk.AssertContainsEntry (apkPath, "assets/foo/foo.txt"); @@ -227,7 +226,7 @@ public Foo () } // Check classes.dex contains foo.jar - var intermediate = Path.Combine (FullProjectDirectory, appA.IntermediateOutputPath); + var intermediate = Path.Combine (Root, appBuilder.ProjectDirectory, appA.IntermediateOutputPath); var dexFile = Path.Combine (intermediate, "android", "bin", "classes.dex"); FileAssert.Exists (dexFile); var proguardFiles = Directory.GetFiles (Path.Combine (intermediate, "lp"), "proguard.txt", SearchOption.AllDirectories); @@ -256,14 +255,20 @@ public Foo () [Test] public void DotNetNew ([Values ("android", "androidlib", "android-bindinglib", "androidwear")] string template) { - var dotnet = CreateDotNetBuilder (); + var templateName = TestName.Replace ("-", ""); + var templatePath = Path.Combine (Root, "temp", templateName); + if (Directory.Exists (templatePath)) + Directory.Delete (templatePath, true); + + TestOutputDirectories [TestContext.CurrentContext.Test.ID] = templatePath; + var dotnet = new DotNetCLI (Path.Combine (templatePath, $"{templateName}.csproj")); Assert.IsTrue (dotnet.New (template), $"`dotnet new {template}` should succeed"); File.WriteAllBytes (Path.Combine (dotnet.ProjectDirectory, "foo.jar"), ResourceData.JavaSourceJarTestJar); Assert.IsTrue (dotnet.New ("android-activity"), "`dotnet new android-activity` should succeed"); Assert.IsTrue (dotnet.New ("android-layout", Path.Combine (dotnet.ProjectDirectory, "Resources", "layout")), "`dotnet new android-layout` should succeed"); // Debug build - Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); + Assert.IsTrue (dotnet.Build (parameters: new [] { "Configuration=Debug" }), "`dotnet build` should succeed"); dotnet.AssertHasNoWarnings (); // Release build @@ -299,9 +304,10 @@ public void DotNetNew ([Values ("android", "androidlib", "android-bindinglib", " public void DotNetPack (string dotnetVersion, string platform, int apiLevel) { var targetFramework = $"{dotnetVersion}-{platform}"; - var proj = new XASdkProject (outputType: "Library") { + var proj = new XamarinAndroidLibraryProject { TargetFramework = targetFramework, IsRelease = true, + EnableDefaultItems = true, Sources = { new BuildItem.Source ("Foo.cs") { TextContent = () => "public class Foo { }", @@ -327,7 +333,6 @@ public String Say (String quote) { }, }, }; - proj.AddNuGetSourcesForOlderTargetFrameworks (); if (IsPreviewFrameworkVersion (targetFramework)) { proj.SetProperty ("EnablePreviewFeatures", "true"); } @@ -349,10 +354,12 @@ public String Say (String quote) { MetadataValues = "Pack=false;Bind=false", }); - var dotnet = CreateDotNetBuilder (proj); - Assert.IsTrue (dotnet.Pack (), "`dotnet pack` should succeed"); + var projBuilder = CreateDllBuilder (); + projBuilder.Save (proj); + var dotnet = new DotNetCLI (Path.Combine (Root, projBuilder.ProjectDirectory, proj.ProjectFilePath)); + Assert.IsTrue (dotnet.Pack (parameters: new [] { "Configuration=Release" }), "`dotnet pack` should succeed"); - var nupkgPath = Path.Combine (FullProjectDirectory, proj.OutputPath, "..", $"{proj.ProjectName}.1.0.0.nupkg"); + var nupkgPath = Path.Combine (Root, projBuilder.ProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.1.0.0.nupkg"); FileAssert.Exists (nupkgPath); using var nupkg = ZipHelper.OpenZip (nupkgPath); nupkg.AssertContainsEntry (nupkgPath, $"lib/{dotnetVersion}-android{apiLevel}.0/{proj.ProjectName}.dll"); @@ -370,7 +377,9 @@ public String Say (String quote) { [Test] public void DotNetLibraryAarChanges () { - var proj = new XASdkProject (outputType: "Library"); + var proj = new XamarinAndroidLibraryProject () { + EnableDefaultItems = true, + }; proj.Sources.Add (new AndroidItem.AndroidResource ("Resources\\raw\\foo.txt") { TextContent = () => "foo", }); @@ -378,9 +387,9 @@ public void DotNetLibraryAarChanges () TextContent = () => "bar", }); - var dotnet = CreateDotNetBuilder (proj); - Assert.IsTrue (dotnet.Build (), "first build should succeed"); - var aarPath = Path.Combine (FullProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.aar"); + var builder = CreateDllBuilder (); + Assert.IsTrue (builder.Build (proj, doNotCleanupOnUpdate: true), "first build should succeed"); + var aarPath = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.aar"); FileAssert.Exists (aarPath); using (var aar = ZipHelper.OpenZip (aarPath)) { aar.AssertEntryContents (aarPath, "res/raw/foo.txt", contents: "foo"); @@ -389,9 +398,9 @@ public void DotNetLibraryAarChanges () // Change res/raw/bar.txt contents WaitFor (1000); - var bar_txt = Path.Combine (FullProjectDirectory, "Resources", "raw", "bar.txt"); + var bar_txt = Path.Combine (Root, builder.ProjectDirectory, "Resources", "raw", "bar.txt"); File.WriteAllText (bar_txt, contents: "baz"); - Assert.IsTrue (dotnet.Build (), "second build should succeed"); + Assert.IsTrue (builder.Build (proj, doNotCleanupOnUpdate: true), "second build should succeed"); FileAssert.Exists (aarPath); using (var aar = ZipHelper.OpenZip (aarPath)) { aar.AssertEntryContents (aarPath, "res/raw/foo.txt", contents: "foo"); @@ -400,7 +409,8 @@ public void DotNetLibraryAarChanges () // Delete res/raw/bar.txt File.Delete (bar_txt); - Assert.IsTrue (dotnet.Build (), "third build should succeed"); + proj.Sources.Remove (proj.Sources.Last ()); + Assert.IsTrue (builder.Build (proj), "third build should succeed"); FileAssert.Exists (aarPath); using (var aar = ZipHelper.OpenZip (aarPath)) { aar.AssertEntryContents (aarPath, "res/raw/foo.txt", contents: "foo"); @@ -411,7 +421,8 @@ public void DotNetLibraryAarChanges () [Test] public void AppWithSingleJar () { - var proj = new XASdkProject { + var proj = new XamarinAndroidApplicationProject { + EnableDefaultItems = true, Sources = { new AndroidItem.AndroidLibrary ("Jars\\javaclasses.jar") { BinaryContent = () => ResourceData.JavaSourceJarTestJar, @@ -419,10 +430,10 @@ public void AppWithSingleJar () } }; - var dotnet = CreateDotNetBuilder (proj); - Assert.IsTrue (dotnet.Build (), "first build should succeed"); + var builder = CreateApkBuilder (); + Assert.IsTrue (builder.Build (proj), "first build should succeed"); - var assemblyPath = Path.Combine (FullProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll"); + var assemblyPath = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll"); var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest"; FileAssert.Exists (assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath)) { @@ -431,8 +442,8 @@ public void AppWithSingleJar () // Remove the @(AndroidLibrary) & build again proj.Sources.RemoveAt (proj.Sources.Count - 1); - Directory.Delete (Path.Combine (FullProjectDirectory, "Jars"), recursive: true); - Assert.IsTrue (dotnet.Build (), "second build should succeed"); + Directory.Delete (Path.Combine (Root, builder.ProjectDirectory, "Jars"), recursive: true); + Assert.IsTrue (builder.Build (proj), "second build should succeed"); FileAssert.Exists (assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath)) { @@ -444,8 +455,9 @@ public void AppWithSingleJar () public void GenerateResourceDesigner([Values (false, true)] bool generateResourceDesigner, [Values (false, true)] bool useDesignerAssembly) { var path = Path.Combine ("temp", TestName); - var libraryB = new XASdkProject (outputType: "Library") { + var libraryB = new XamarinAndroidLibraryProject { ProjectName = "LibraryB", + EnableDefaultItems = true, }; libraryB.Sources.Clear (); libraryB.Sources.Add (new BuildItem.Source ("Foo.cs") { @@ -458,8 +470,9 @@ public class Foo { BinaryContent = () => XamarinAndroidCommonProject.icon_binary_mdpi, }); libraryB.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); - var libraryA = new XASdkProject (outputType: "Library") { + var libraryA = new XamarinAndroidLibraryProject { ProjectName = "LibraryA", + EnableDefaultItems = true, }; libraryA.Sources.Clear (); libraryA.Sources.Add (new BuildItem.Source ("FooA.cs") { @@ -474,29 +487,33 @@ public class FooA { libraryA.SetProperty ("AndroidGenerateResourceDesigner", generateResourceDesigner.ToString ()); if (!useDesignerAssembly) libraryA.SetProperty ("AndroidUseDesignerAssembly", "False"); - var libraryBBuilder = CreateDotNetBuilder (libraryB, Path.Combine (path, libraryB.ProjectName)); - Assert.IsTrue (libraryBBuilder.Build (), "Build of LibraryB should succeed."); - var libraryABuilder = CreateDotNetBuilder (libraryA, Path.Combine (path, libraryA.ProjectName)); - Assert.IsTrue (libraryABuilder.Build (), "Build of LibraryA should succeed."); - var proj = new XASdkProject () { + var libraryBBuilder = CreateDllBuilder (Path.Combine (path, libraryB.ProjectName)); + Assert.IsTrue (libraryBBuilder.Build (libraryB), "Build of LibraryB should succeed."); + var libraryABuilder = CreateDllBuilder (Path.Combine (path, libraryA.ProjectName)); + Assert.IsTrue (libraryABuilder.Build (libraryA), "Build of LibraryA should succeed."); + var proj = new XamarinAndroidApplicationProject { ProjectName = "App1", + EnableDefaultItems = true, }; proj.SetProperty ("AndroidUseDesignerAssembly", useDesignerAssembly.ToString ()); proj.AddReference (libraryA); - var dotnet = CreateDotNetBuilder (proj, Path.Combine (path, proj.ProjectName)); - Assert.IsTrue (dotnet.Build (), "Build of Proj should succeed."); + var builder = CreateApkBuilder (); + Assert.IsTrue (builder.Build (proj), "Build of Proj should succeed."); } [Test] public void GenerateResourceDesigner_false([Values (false, true)] bool useDesignerAssembly) { - var proj = new XASdkProject (outputType: "Library") { + var proj = new XamarinAndroidApplicationProject { + EnableDefaultItems = true, Sources = { new AndroidItem.AndroidResource (() => "Resources\\drawable\\foo.png") { BinaryContent = () => XamarinAndroidCommonProject.icon_binary_mdpi, }, } }; + proj.SetProperty (KnownProperties.OutputType, "Library"); + // Turn off Resource.designer.cs and remove usage of it proj.SetProperty ("AndroidGenerateResourceDesigner", "false"); if (!useDesignerAssembly) @@ -505,22 +522,22 @@ public void GenerateResourceDesigner_false([Values (false, true)] bool useDesign .Replace ("Resource.Layout.Main", "0") .Replace ("Resource.Id.myButton", "0"); - var dotnet = CreateDotNetBuilder (proj); - Assert.IsTrue (dotnet.Build(target: "CoreCompile", parameters: new string[] { "BuildingInsideVisualStudio=true" }), "Designtime build should succeed."); - var intermediate = Path.Combine (FullProjectDirectory, proj.IntermediateOutputPath); + var builder = CreateDllBuilder (); + Assert.IsTrue (builder.RunTarget(proj, "CoreCompile", parameters: new string[] { "BuildingInsideVisualStudio=true" }), "Designtime build should succeed."); + var intermediate = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath); var resource_designer_cs = Path.Combine (intermediate, "designtime", "Resource.designer.cs"); if (useDesignerAssembly) resource_designer_cs = Path.Combine (intermediate, "__Microsoft.Android.Resource.Designer.cs"); FileAssert.DoesNotExist (resource_designer_cs); - Assert.IsTrue (dotnet.Build (), "build should succeed"); + Assert.IsTrue (builder.Build (proj), "build should succeed"); resource_designer_cs = Path.Combine (intermediate, "Resource.designer.cs"); if (useDesignerAssembly) resource_designer_cs = Path.Combine (intermediate, "__Microsoft.Android.Resource.Designer.cs"); FileAssert.DoesNotExist (resource_designer_cs); - var assemblyPath = Path.Combine (FullProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll"); + var assemblyPath = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll"); FileAssert.Exists (assemblyPath); using var assembly = AssemblyDefinition.ReadAssembly (assemblyPath); var typeName = $"{proj.ProjectName}.Resource"; @@ -531,7 +548,9 @@ public void GenerateResourceDesigner_false([Values (false, true)] bool useDesign [Test] public void DotNetBuildBinding () { - var proj = new XASdkProject (outputType: "Library"); + var proj = new XamarinAndroidLibraryProject () { + EnableDefaultItems = true, + }; // Both transform files should be applied proj.Sources.Add (new AndroidItem.TransformFile ("Transforms.xml") { TextContent = () => @@ -556,10 +575,10 @@ public void DotNetBuildBinding () TextContent = () => ResourceData.JavaSourceTestExtension, Metadata = { { "Bind", "True"} }, }); - var dotnet = CreateDotNetBuilder (proj); - Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); + var builder = CreateDllBuilder (); + Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); - var assemblyPath = Path.Combine (FullProjectDirectory, proj.OutputPath, "UnnamedProject.dll"); + var assemblyPath = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath, "UnnamedProject.dll"); FileAssert.Exists (assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath)) { var typeName = "MSBuildTest.JavaSourceJarTest"; @@ -675,8 +694,9 @@ public void DotNetBuildBinding () [TestCaseSource (nameof (DotNetBuildSource))] public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bool usesAssemblyStore) { - var proj = new XASdkProject { + var proj = new XamarinAndroidApplicationProject { IsRelease = isRelease, + EnableDefaultItems = true, ExtraNuGetConfigSources = { // Microsoft.AspNetCore.Components.WebView is not in dotnet-public "https://api.nuget.org/v3/index.json", @@ -727,12 +747,12 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo proj.SetProperty (KnownProperties.RuntimeIdentifiers, runtimeIdentifiers); } - var dotnet = CreateDotNetBuilder (proj); - Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); - dotnet.AssertHasNoWarnings (); + var builder = CreateApkBuilder (); + Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); + builder.AssertHasNoWarnings (); - var outputPath = Path.Combine (FullProjectDirectory, proj.OutputPath); - var intermediateOutputPath = Path.Combine (FullProjectDirectory, proj.IntermediateOutputPath); + var outputPath = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath); + var intermediateOutputPath = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath); if (!runtimeIdentifiers.Contains (";")) { outputPath = Path.Combine (outputPath, runtimeIdentifiers); intermediateOutputPath = Path.Combine (intermediateOutputPath, runtimeIdentifiers); @@ -811,11 +831,11 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo [Test] public void DotNetBuildXamarinForms ([Values (true, false)] bool useInterpreter) { - var proj = new XamarinFormsXASdkProject (); + var proj = new XamarinFormsAndroidApplicationProject (); proj.SetProperty ("UseInterpreter", useInterpreter.ToString ()); - var dotnet = CreateDotNetBuilder (proj); - Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); - dotnet.AssertHasNoWarnings (); + var builder = CreateApkBuilder (); + Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); + builder.AssertHasNoWarnings (); } static readonly object[] DotNetTargetFrameworks = new object[] { @@ -866,11 +886,11 @@ public void DotNetPublish ([Values (false, true)] bool isRelease, [ValueSource(n var targetFramework = $"{dotnetVersion}-{platform}"; const string runtimeIdentifier = "android-arm"; - var proj = new XASdkProject { + var proj = new XamarinAndroidApplicationProject { TargetFramework = targetFramework, IsRelease = isRelease, + EnableDefaultItems = true, }; - proj.AddNuGetSourcesForOlderTargetFrameworks (); proj.SetProperty (KnownProperties.RuntimeIdentifier, runtimeIdentifier); var preview = IsPreviewFrameworkVersion (targetFramework); @@ -878,8 +898,12 @@ public void DotNetPublish ([Values (false, true)] bool isRelease, [ValueSource(n proj.SetProperty ("EnablePreviewFeatures", "true"); } - var dotnet = CreateDotNetBuilder (proj); - Assert.IsTrue (dotnet.Publish (), "first `dotnet publish` should succeed"); + var projBuilder = CreateDllBuilder (); + projBuilder.Save (proj); + var dotnet = new DotNetCLI (Path.Combine (Root, projBuilder.ProjectDirectory, proj.ProjectFilePath)); + string[] configParam = isRelease ? new [] { "Configuration=Release" } : new [] { "Configuration=Debug" }; + Assert.IsTrue (dotnet.Publish (parameters: configParam), "first `dotnet publish` should succeed"); + // NOTE: Preview API levels emit XA4211 if (!preview) { // TODO: disabled in .NET 7 due to: https://github.com/dotnet/runtime/issues/77385 @@ -899,7 +923,7 @@ public void DotNetPublish ([Values (false, true)] bool isRelease, [ValueSource(n Assert.IsTrue (dotnet.LastBuildOutput.ContainsText (expectedMonoAndroidRuntimePath), $"Build should be using {expectedMonoAndroidRuntimePath}"); } - var publishDirectory = Path.Combine (FullProjectDirectory, proj.OutputPath, runtimeIdentifier, "publish"); + var publishDirectory = Path.Combine (Root, projBuilder.ProjectDirectory, proj.OutputPath, runtimeIdentifier, "publish"); var apk = Path.Combine (publishDirectory, $"{proj.PackageName}.apk"); var apkSigned = Path.Combine (publishDirectory, $"{proj.PackageName}-Signed.apk"); // NOTE: the unsigned .apk doesn't exist when $(AndroidPackageFormats) is `aab;apk` @@ -920,32 +944,36 @@ public void DotNetPublish ([Values (false, true)] bool isRelease, [ValueSource(n [Test] public void DefaultItems () { - void CreateEmptyFile (params string [] paths) + void CreateEmptyFile (string path) { - var path = Path.Combine (FullProjectDirectory, Path.Combine (paths)); Directory.CreateDirectory (Path.GetDirectoryName (path)); File.WriteAllText (path, contents: ""); } - var proj = new XASdkProject (); - var dotnet = CreateDotNetBuilder (proj); + var proj = new XamarinAndroidApplicationProject () { + EnableDefaultItems = true, + }; + + var builder = CreateApkBuilder (); + builder.Save (proj); + proj.ShouldPopulate = false; // Build error -> no nested sub-directories in Resources - CreateEmptyFile ("Resources", "drawable", "foo", "bar.png"); - CreateEmptyFile ("Resources", "raw", "foo", "bar.png"); + CreateEmptyFile (Path.Combine (Root, builder.ProjectDirectory, "Resources", "drawable", "foo", "bar.png")); + CreateEmptyFile (Path.Combine (Root, builder.ProjectDirectory, "Resources", "raw", "foo", "bar.png")); // Build error -> no files/directories that start with . - CreateEmptyFile ("Resources", "raw", ".DS_Store"); - CreateEmptyFile ("Assets", ".DS_Store"); - CreateEmptyFile ("Assets", ".svn", "foo.txt"); + CreateEmptyFile (Path.Combine (Root, builder.ProjectDirectory, "Resources", "raw", ".DS_Store")); + CreateEmptyFile (Path.Combine (Root, builder.ProjectDirectory, "Assets", ".DS_Store")); + CreateEmptyFile (Path.Combine (Root, builder.ProjectDirectory, "Assets", ".svn", "foo.txt")); // Files that should work - CreateEmptyFile ("Resources", "raw", "foo.txt"); - CreateEmptyFile ("Assets", "foo", "bar.txt"); + CreateEmptyFile (Path.Combine (Root, builder.ProjectDirectory, "Resources", "raw", "foo.txt")); + CreateEmptyFile (Path.Combine (Root, builder.ProjectDirectory, "Assets", "foo", "bar.txt")); - Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); + Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); - var apkPath = Path.Combine (FullProjectDirectory, proj.OutputPath, $"{proj.PackageName}-Signed.apk"); + var apkPath = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath, $"{proj.PackageName}-Signed.apk"); FileAssert.Exists (apkPath); using (var apk = ZipHelper.OpenZip (apkPath)) { apk.AssertContainsEntry (apkPath, "res/raw/foo.txt"); @@ -956,26 +984,27 @@ void CreateEmptyFile (params string [] paths) [Test] public void XamarinLegacySdk ([Values ("net7.0-android33.0", "net8.0-android33.0")] string dotnetTargetFramework) { - var proj = new XASdkProject (outputType: "Library") { + var proj = new XamarinAndroidLibraryProject { Sdk = "Xamarin.Legacy.Sdk/0.2.0-alpha4", + EnableDefaultItems = true, Sources = { new AndroidItem.AndroidLibrary ("javaclasses.jar") { BinaryContent = () => ResourceData.JavaSourceJarTestJar, } } }; - proj.AddNuGetSourcesForOlderTargetFrameworks (dotnetTargetFramework); - using var b = new Builder (); var legacyTargetFrameworkVersion = "13.0"; var legacyTargetFramework = $"monoandroid{legacyTargetFrameworkVersion}"; proj.SetProperty ("TargetFramework", value: ""); proj.SetProperty ("TargetFrameworks", value: $"{dotnetTargetFramework};{legacyTargetFramework}"); - var dotnet = CreateDotNetBuilder (proj); - Assert.IsTrue (dotnet.Pack (), "`dotnet pack` should succeed"); + var projBuilder = CreateDllBuilder (); + projBuilder.Save (proj); + var dotnet = new DotNetCLI (Path.Combine (Root, projBuilder.ProjectDirectory, proj.ProjectFilePath)); + Assert.IsTrue (dotnet.Pack (parameters: new [] { "Configuration=Debug" }), "`dotnet pack` should succeed"); - var nupkgPath = Path.Combine (FullProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.1.0.0.nupkg"); + var nupkgPath = Path.Combine (Root, projBuilder.ProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.1.0.0.nupkg"); FileAssert.Exists (nupkgPath); using var nupkg = ZipHelper.OpenZip (nupkgPath); nupkg.AssertContainsEntry (nupkgPath, $"lib/{dotnetTargetFramework}/{proj.ProjectName}.dll"); @@ -990,10 +1019,10 @@ public void MauiTargetFramework (string dotnetVersion, string platform, int apiL Assert.Ignore ($"Test for API level {apiLevel} was skipped as it matched the default or latest stable API level."); var targetFramework = $"{dotnetVersion}-{platform}"; - var library = new XASdkProject (outputType: "Library") { + var library = new XamarinAndroidLibraryProject { TargetFramework = targetFramework, + EnableDefaultItems = true, }; - library.AddNuGetSourcesForOlderTargetFrameworks (); var preview = IsPreviewFrameworkVersion (targetFramework); if (preview) { @@ -1017,11 +1046,11 @@ public abstract class Foo : ViewHandler Lib B var path = Path.Combine ("temp", TestName); - var libB = new XASdkProject (outputType: "Library") { + var libB = new XamarinAndroidLibraryProject { ProjectName = "LibraryB", IsRelease = isRelease, + EnableDefaultItems = true, }; libB.Sources.Clear (); libB.Sources.Add (new BuildItem.Source ("Foo.cs") { TextContent = () => "public class Foo { }", }); - // Will save the project, does not need to build it - CreateDotNetBuilder (libB, Path.Combine (path, libB.ProjectName)); + var libBBuilder = CreateDllBuilder (Path.Combine (path, libB.ProjectName)); + Assert.IsTrue (libBBuilder.Build(libB), $"{libB.ProjectName} should build"); - var appA = new XASdkProject { + var appA = new XamarinAndroidApplicationProject { ProjectName = "AppA", IsRelease = isRelease, + EnableDefaultItems = true, Sources = { new BuildItem.Source ("Bar.cs") { TextContent = () => "public class Bar : Foo { }", @@ -1053,22 +1084,23 @@ public void DotNetIncremental ([Values (true, false)] bool isRelease, [Values (" } }; appA.AddReference (libB); - var appBuilder = CreateDotNetBuilder (appA, Path.Combine (path, appA.ProjectName)); + var appBuilder = CreateApkBuilder (Path.Combine (path, appA.ProjectName)); appBuilder.BuildLogFile = Path.Combine (Root, path, appA.ProjectName, "build1.log"); - Assert.IsTrue (appBuilder.Build (runtimeIdentifier: runtimeIdentifier), $"{appA.ProjectName} should succeed"); - appBuilder.AssertTargetIsNotSkipped ("CoreCompile", occurrence: 1); + appA.SetProperty (KnownProperties.RuntimeIdentifier, runtimeIdentifier); + Assert.IsTrue (appBuilder.Build (appA), $"{appA.ProjectName} should succeed"); + appBuilder.Output.AssertTargetIsNotSkipped ("CoreCompile", occurrence: 1); if (isRelease) { - appBuilder.AssertTargetIsNotSkipped ("_RemoveRegisterAttribute"); - appBuilder.AssertTargetIsNotSkipped ("_AndroidAot"); + appBuilder.Output.AssertTargetIsNotSkipped ("_RemoveRegisterAttribute"); + appBuilder.Output.AssertTargetIsNotSkipped ("_AndroidAot"); } // Build again, no changes appBuilder.BuildLogFile = Path.Combine (Root, path, appA.ProjectName, "build2.log"); - Assert.IsTrue (appBuilder.Build (runtimeIdentifier: runtimeIdentifier), $"{appA.ProjectName} should succeed"); - appBuilder.AssertTargetIsSkipped ("CoreCompile", occurrence: 2); + Assert.IsTrue (appBuilder.Build (appA), $"{appA.ProjectName} should succeed"); + appBuilder.Output.AssertTargetIsSkipped ("CoreCompile", occurrence: 2); if (isRelease) { - appBuilder.AssertTargetIsSkipped ("_RemoveRegisterAttribute"); - appBuilder.AssertTargetIsSkipped ("_AndroidAotCompilation"); + appBuilder.Output.AssertTargetIsSkipped ("_RemoveRegisterAttribute"); + appBuilder.Output.AssertTargetIsSkipped ("_AndroidAotCompilation"); } } @@ -1078,7 +1110,7 @@ public void ProjectDependencies ([Values(true, false)] bool projectReference) // Setup dependencies App A -> Lib B -> Lib C var path = Path.Combine ("temp", TestName); - var libB = new XASdkProject (outputType: "Library") { + var libB = new XamarinAndroidLibraryProject () { ProjectName = "LibraryB", IsRelease = true, }; @@ -1091,9 +1123,10 @@ public Foo () { }", }); - var libC = new XASdkProject (outputType: "Library") { + var libC = new XamarinAndroidLibraryProject () { ProjectName = "LibraryC", IsRelease = true, + AppendTargetFrameworkToOutputPath = true, }; libC.Sources.Clear (); libC.Sources.Add (new BuildItem.Source ("Bar.cs") { @@ -1114,12 +1147,12 @@ public Foo () { } // Build libraries - var libCBuilder = CreateDotNetBuilder (libC, Path.Combine (path, libC.ProjectName)); - Assert.IsTrue (libCBuilder.Build (), $"{libC.ProjectName} should succeed"); - var libBBuilder = CreateDotNetBuilder (libB, Path.Combine (path, libB.ProjectName)); - Assert.IsTrue (libBBuilder.Build (), $"{libB.ProjectName} should succeed"); + var libCBuilder = CreateDllBuilder (Path.Combine (path, libC.ProjectName)); + Assert.IsTrue (libCBuilder.Build (libC), $"{libC.ProjectName} should succeed"); + var libBBuilder = CreateDllBuilder (Path.Combine (path, libB.ProjectName)); + Assert.IsTrue (libBBuilder.Build (libB), $"{libB.ProjectName} should succeed"); - var appA = new XASdkProject { + var appA = new XamarinAndroidApplicationProject { ProjectName = "AppA", IsRelease = true, Sources = { @@ -1135,10 +1168,10 @@ public Foo () { } }; appA.AddReference (libB); - var appBuilder = CreateDotNetBuilder (appA, Path.Combine (path, appA.ProjectName)); - Assert.IsTrue (appBuilder.Build (), $"{appA.ProjectName} should succeed"); + var appBuilder = CreateApkBuilder (Path.Combine (path, appA.ProjectName)); + Assert.IsTrue (appBuilder.Build (appA), $"{appA.ProjectName} should succeed"); - var apkPath = Path.Combine (FullProjectDirectory, appA.OutputPath, $"{appA.PackageName}-Signed.apk"); + var apkPath = Path.Combine (Root, appBuilder.ProjectDirectory, appA.OutputPath, $"{appA.PackageName}-Signed.apk"); FileAssert.Exists (apkPath); var helper = new ArchiveAssemblyHelper (apkPath); helper.AssertContainsEntry ($"assemblies/{appA.ProjectName}.dll"); @@ -1151,45 +1184,39 @@ public Foo () { [Test] public void DotNetDesignTimeBuild () { - var proj = new XASdkProject (); + var proj = new XamarinAndroidApplicationProject () { + EnableDefaultItems = true, + }; proj.SetProperty ("AndroidUseDesignerAssembly", "true"); - var builder = CreateDotNetBuilder (proj); + var builder = CreateApkBuilder (); var parameters = new [] { "BuildingInsideVisualStudio=true"}; builder.BuildLogFile = "update.log"; - Assert.IsTrue (builder.Build ("Compile", parameters: parameters), $"{proj.ProjectName} should succeed"); - builder.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 1); - builder.AssertTargetIsNotSkipped ("_GenerateRtxt"); - builder.AssertTargetIsNotSkipped ("_GenerateResourceDesignerIntermediateClass"); - builder.AssertTargetIsNotSkipped ("_GenerateResourceDesignerAssembly", occurrence: 1); + Assert.IsTrue (builder.RunTarget (proj, "Compile", parameters: parameters), $"{proj.ProjectName} should succeed"); + builder.Output.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 1); + builder.Output.AssertTargetIsNotSkipped ("_GenerateRtxt"); + builder.Output.AssertTargetIsNotSkipped ("_GenerateResourceDesignerIntermediateClass"); + builder.Output.AssertTargetIsNotSkipped ("_GenerateResourceDesignerAssembly", occurrence: 1); parameters = new [] { "BuildingInsideVisualStudio=true" }; builder.BuildLogFile = "build1.log"; - Assert.IsTrue (builder.Build ("SignAndroidPackage", parameters: parameters), $"{proj.ProjectName} should succeed"); - builder.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 2); - builder.AssertTargetIsSkipped ("_GenerateRtxt", occurrence: 1); - builder.AssertTargetIsSkipped ("_GenerateResourceDesignerIntermediateClass", occurrence: 1); - builder.AssertTargetIsSkipped ("_GenerateResourceDesignerAssembly", occurrence: 2); + Assert.IsTrue (builder.RunTarget (proj, "SignAndroidPackage", parameters: parameters), $"{proj.ProjectName} should succeed"); + builder.Output.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 2); + builder.Output.AssertTargetIsSkipped ("_GenerateRtxt", occurrence: 1); + builder.Output.AssertTargetIsSkipped ("_GenerateResourceDesignerIntermediateClass", occurrence: 1); + builder.Output.AssertTargetIsSkipped ("_GenerateResourceDesignerAssembly", occurrence: 2); builder.BuildLogFile = "build2.log"; - Assert.IsTrue (builder.Build ("SignAndroidPackage", parameters: parameters), $"{proj.ProjectName} should succeed 2"); - builder.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 3); - builder.AssertTargetIsSkipped ("_GenerateRtxt", occurrence: 2); - builder.AssertTargetIsSkipped ("_GenerateResourceDesignerIntermediateClass", occurrence: 2); - builder.AssertTargetIsSkipped ("_GenerateResourceDesignerAssembly"); - } - - [Test] - public void SignAndroidPackage () - { - var proj = new XASdkProject (); - var builder = CreateDotNetBuilder (proj); - var parameters = new [] { "BuildingInsideVisualStudio=true" }; - Assert.IsTrue (builder.Build ("SignAndroidPackage", parameters: parameters), $"{proj.ProjectName} should succeed"); + Assert.IsTrue (builder.RunTarget (proj, "SignAndroidPackage", parameters: parameters), $"{proj.ProjectName} should succeed 2"); + builder.Output.AssertTargetIsNotSkipped ("_GenerateResourceCaseMap", occurrence: 3); + builder.Output.AssertTargetIsSkipped ("_GenerateRtxt", occurrence: 2); + builder.Output.AssertTargetIsSkipped ("_GenerateResourceDesignerIntermediateClass", occurrence: 2); + builder.Output.AssertTargetIsSkipped ("_GenerateResourceDesignerAssembly"); } [Test] public void WearProjectJavaBuildFailure () { - var proj = new XASdkProject { + var proj = new XamarinAndroidApplicationProject { IsRelease = true, + EnableDefaultItems = true, PackageReferences = { new Package { Id = "Xamarin.AndroidX.Wear", Version = "1.2.0.5" }, new Package { Id = "Xamarin.Android.Wear", Version = "2.2.0" }, @@ -1198,8 +1225,9 @@ public void WearProjectJavaBuildFailure () }, SupportedOSPlatformVersion = "23", }; - var builder = CreateDotNetBuilder (proj); - Assert.IsFalse (builder.Build (), $"{proj.ProjectName} should fail."); + var builder = CreateApkBuilder (); + builder.ThrowOnBuildFailure = false; + Assert.IsFalse (builder.Build (proj), $"{proj.ProjectName} should fail."); var text = $"java.lang.RuntimeException"; Assert.IsTrue (StringAssertEx.ContainsText (builder.LastBuildOutput, text), $"Output did not contain '{text}'"); text = $"is defined multiple times"; @@ -1211,13 +1239,14 @@ public void WearProjectJavaBuildFailure () [Test] public void BenchmarkDotNet () { - var proj = new XASdkProject { + var proj = new XamarinAndroidApplicationProject { + EnableDefaultItems = true, PackageReferences = { new Package { Id = "BenchmarkDotNet", Version = "0.13.1" }, } }; - var builder = CreateDotNetBuilder (proj); - Assert.IsTrue (builder.Build (), $"{proj.ProjectName} should succeed"); + var builder = CreateApkBuilder (); + Assert.IsTrue (builder.Build (proj), $"{proj.ProjectName} should succeed"); builder.AssertHasNoWarnings (); } @@ -1260,49 +1289,29 @@ public void BenchmarkDotNet () [TestCaseSource (nameof (SettingCombinationsSource))] public void SettingCombinations (bool isRelease, bool useInterpreter, bool publishTrimmed, bool aot, bool expected) { - var proj = new XASdkProject { + var proj = new XamarinAndroidApplicationProject { IsRelease = isRelease, + EnableDefaultItems = true, }; proj.SetProperty ("UseInterpreter", useInterpreter.ToString ()); proj.SetProperty ("PublishTrimmed", publishTrimmed.ToString ()); proj.SetProperty ("RunAOTCompilation", aot.ToString ()); - var builder = CreateDotNetBuilder (proj); - Assert.AreEqual (expected, builder.Build (), $"{proj.ProjectName} should {(expected ? "succeed" : "fail")}"); + var builder = CreateApkBuilder (); + builder.ThrowOnBuildFailure = false; + Assert.AreEqual (expected, builder.Build (proj), $"{proj.ProjectName} should {(expected ? "succeed" : "fail")}"); } [Test] public void EolFrameworks() { - var library = new XASdkProject (outputType: "Library") { + var library = new XamarinAndroidLibraryProject () { TargetFramework = "net6.0-android", + EnableDefaultItems = true, }; - var dotnet = CreateDotNetBuilder (library); - Assert.IsFalse (dotnet.Restore (), $"{library.ProjectName} should fail"); - Assert.IsTrue (StringAssertEx.ContainsText (dotnet.LastBuildOutput, "NETSDK1202"), $"{dotnet.BuildLogFile} should have NETSDK1202."); - } - - DotNetCLI CreateDotNetBuilder (string relativeProjectDir = null) - { - if (string.IsNullOrEmpty (relativeProjectDir)) { - relativeProjectDir = Path.Combine ("temp", TestName); - } - TestOutputDirectories [TestContext.CurrentContext.Test.ID] = - FullProjectDirectory = Path.Combine (Root, relativeProjectDir); - new XASdkProject ().CopyNuGetConfig (relativeProjectDir); - return new DotNetCLI (Path.Combine (FullProjectDirectory, $"{TestName}.csproj")); - } - - DotNetCLI CreateDotNetBuilder (XASdkProject project, string relativeProjectDir = null) - { - if (string.IsNullOrEmpty (relativeProjectDir)) { - relativeProjectDir = Path.Combine ("temp", TestName); - } - TestOutputDirectories [TestContext.CurrentContext.Test.ID] = - FullProjectDirectory = Path.Combine (Root, relativeProjectDir); - var files = project.Save (); - project.Populate (relativeProjectDir, files); - project.CopyNuGetConfig (relativeProjectDir); - return new DotNetCLI (project, Path.Combine (FullProjectDirectory, project.ProjectFilePath)); + var builder = CreateApkBuilder (); + builder.ThrowOnBuildFailure = false; + Assert.IsFalse (builder.Restore (library), $"{library.ProjectName} restore should fail"); + Assert.IsTrue (StringAssertEx.ContainsText (builder.LastBuildOutput, "NETSDK1202"), $"{builder.BuildLogFile} should have NETSDK1202."); } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs deleted file mode 100644 index 6bdab872fd3..00000000000 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Xml.Linq; -using System.Runtime.CompilerServices; - -namespace Xamarin.ProjectTools -{ - public class XASdkProject : DotNetStandard - { - const string default_strings_xml = @" - - Hello World, Click Me! - ${PROJECT_NAME} - -"; - - static readonly string default_layout_main; - static readonly string default_main_activity_cs; - static readonly string default_android_manifest; - static readonly byte [] icon_binary_mdpi; - - static XASdkProject () - { - var assembly = typeof (XASdkProject).Assembly; - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Base.AndroidManifest.xml"))) - default_android_manifest = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.DotNet.MainActivity.cs"))) - default_main_activity_cs = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Base.LayoutMain.axml"))) - default_layout_main = sr.ReadToEnd (); - using (var stream = assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Base.Icon.png")) { - icon_binary_mdpi = new byte [stream.Length]; - stream.Read (icon_binary_mdpi, 0, (int) stream.Length); - } - } - - /// - /// Save a NuGet.config file to a directory, with sources to support a local build of Microsoft.Android.Sdk - /// - public static void SaveNuGetConfig (string directory) - { - var doc = XDocument.Load (Path.Combine (XABuildPaths.TopDirectory, "NuGet.config")); - var project = new XASdkProject (); - project.AddNuGetConfigSources (doc); - doc.Save (Path.Combine (directory, "NuGet.config")); - } - - public string PackageName { get; set; } - public string JavaPackageName { get; set; } - - public XASdkProject (string outputType = "Exe", [CallerMemberName] string packageName = "") - { - Sdk = "Microsoft.NET.Sdk"; - TargetFramework = "net8.0-android"; - SupportedOSPlatformVersion = "21"; - PackageName = $"com.xamarin.{(packageName ?? ProjectName).ToLower ()}"; - JavaPackageName = JavaPackageName ?? PackageName.ToLowerInvariant (); - GlobalPackagesFolder = FileSystemUtils.FindNugetGlobalPackageFolder (); - SetProperty (KnownProperties.OutputType, outputType); - SetProperty (KnownProperties.Nullable, "enable"); - SetProperty (KnownProperties.ImplicitUsings, "enable"); - // Disables the transitive restore of packages like Microsoft.AspNetCore.App.Ref, Microsoft.WindowsDesktop.App.Ref - SetProperty ("DisableTransitiveFrameworkReferenceDownloads", "true"); - - // Add relevant Android content to our project without writing it to the .csproj file - if (outputType == "Exe") { - Sources.Add (new BuildItem.Source ("AndroidManifest.xml") { - TextContent = ProcessManifestTemplate - }); - } - Sources.Add (new BuildItem.Source ($"MainActivity{Language.DefaultExtension}") { TextContent = () => ProcessSourceTemplate (MainActivity ?? DefaultMainActivity) }); - Sources.Add (new BuildItem.Source ("Resources\\layout\\Main.axml") { TextContent = () => default_layout_main }); - Sources.Add (new BuildItem.Source ("Resources\\values\\Strings.xml") { TextContent = () => default_strings_xml.Replace ("${PROJECT_NAME}", ProjectName) }); - Sources.Add (new BuildItem.Source ("Resources\\drawable-mdpi\\Icon.png") { BinaryContent = () => icon_binary_mdpi }); - Sources.Add (new BuildItem.Source ($"Resources\\Resource.designer{Language.DefaultExtension}") { TextContent = () => string.Empty }); - } - - public string OutputPath => Path.Combine ("bin", Configuration, TargetFramework.ToLowerInvariant ()); - - public string IntermediateOutputPath => Path.Combine ("obj", Configuration, TargetFramework.ToLowerInvariant ()); - - public string DefaultMainActivity => default_main_activity_cs; - - public string MainActivity { get; set; } - - public string AndroidManifest { get; set; } = default_android_manifest; - - /// - /// Defaults to 21.0 - /// - public string SupportedOSPlatformVersion { - get { return GetProperty (KnownProperties.SupportedOSPlatformVersion); } - set { SetProperty (KnownProperties.SupportedOSPlatformVersion, value); } - } - - public virtual string ProcessManifestTemplate () - { - return AndroidManifest - .Replace ("${PROJECT_NAME}", ProjectName) - .Replace ("${PACKAGENAME}", PackageName) - .Replace ("${USES_SDK}", ""); - } - - public override string ProcessSourceTemplate (string source) - { - return source.Replace ("${ROOT_NAMESPACE}", RootNamespace ?? ProjectName) - .Replace ("${PROJECT_NAME}", ProjectName) - .Replace ("${PACKAGENAME}", PackageName) - .Replace ("${JAVA_PACKAGENAME}", JavaPackageName); - } - } -} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinFormsXASdkProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinFormsXASdkProject.cs deleted file mode 100644 index ddfb338d0ba..00000000000 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinFormsXASdkProject.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Runtime.CompilerServices; - -namespace Xamarin.ProjectTools -{ - public class XamarinFormsXASdkProject : XASdkProject - { - static readonly string default_main_activity_cs; - static readonly string colors_xml; - static readonly string styles_xml; - static readonly string Tabbar_xml; - static readonly string Toolbar_xml; - static readonly string MainPage_xaml; - static readonly string MainPage_xaml_cs; - static readonly string App_xaml; - static readonly string App_xaml_cs; - - static XamarinFormsXASdkProject () - { - var assembly = typeof (XamarinFormsXASdkProject).Assembly; - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Forms.MainActivity.cs"))) - default_main_activity_cs = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Forms.colors.xml"))) - colors_xml = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Forms.styles.xml"))) - styles_xml = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.AndroidX.Tabbar.xml"))) - Tabbar_xml = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.AndroidX.Toolbar.xml"))) - Toolbar_xml = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Forms.MainPage.xaml"))) - MainPage_xaml = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Forms.MainPage.xaml.cs"))) - MainPage_xaml_cs = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Forms.App.xaml"))) - App_xaml = sr.ReadToEnd (); - using (var sr = new StreamReader (assembly.GetManifestResourceStream ("Xamarin.ProjectTools.Resources.Forms.App.xaml.cs"))) - App_xaml_cs = sr.ReadToEnd (); - } - - public XamarinFormsXASdkProject (string outputType = "Exe", [CallerMemberName] string packageName = "") - : base (outputType, packageName) - { - // Don't opt into ImplicitUsings - RemoveProperty (KnownProperties.ImplicitUsings); - PackageReferences.Add (KnownPackages.XamarinForms_4_7_0_1142); - - // Workaround for AndroidX, see: https://github.com/xamarin/AndroidSupportComponents/pull/239 - Imports.Add (new Import (() => "Directory.Build.targets") { - TextContent = () => - @" - - - - " - }); - - Sources.Add (new AndroidItem.AndroidResource ("Resources\\values\\colors.xml") { - TextContent = () => colors_xml, - }); - Sources.Add (new AndroidItem.AndroidResource ("Resources\\values\\styles.xml") { - TextContent = () => styles_xml, - }); - Sources.Add (new AndroidItem.AndroidResource ("Resources\\layout\\Tabbar.xml") { - TextContent = () => Tabbar_xml, - }); - Sources.Add (new AndroidItem.AndroidResource ("Resources\\layout\\Toolbar.xml") { - TextContent = () => Toolbar_xml, - }); - Sources.Add (new BuildItem ("EmbeddedResource", "MainPage.xaml") { - TextContent = MainPageXaml, - }); - Sources.Add (new BuildItem.Source ("MainPage.xaml.cs") { - TextContent = () => ProcessSourceTemplate (MainPage_xaml_cs), - }); - Sources.Add (new BuildItem ("EmbeddedResource", "App.xaml") { - TextContent = () => ProcessSourceTemplate (App_xaml), - }); - Sources.Add (new BuildItem.Source ("App.xaml.cs") { - TextContent = () => ProcessSourceTemplate (App_xaml_cs), - }); - - MainActivity = default_main_activity_cs; - } - - protected virtual string MainPageXaml () => ProcessSourceTemplate (MainPage_xaml); - } -} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs index 4468c83bba6..7c0477ceb8c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs @@ -16,7 +16,6 @@ public class DotNetCLI public string JavaSdkPath { get; set; } = AndroidSdkResolver.GetJavaSdkPath (); public string ProjectDirectory { get; set; } - readonly XASdkProject project; readonly string projectOrSolution; public DotNetCLI (string projectOrSolution) @@ -25,12 +24,6 @@ public DotNetCLI (string projectOrSolution) ProjectDirectory = Path.GetDirectoryName (projectOrSolution); } - public DotNetCLI (XASdkProject project, string projectOrSolution) - : this (projectOrSolution) - { - this.project = project; - } - /// /// Runs the `dotnet` tool with the specified arguments. /// @@ -38,8 +31,10 @@ public DotNetCLI (XASdkProject project, string projectOrSolution) /// Whether or not the command succeeded. protected bool Execute (params string [] args) { - if (string.IsNullOrEmpty (ProcessLogFile)) - ProcessLogFile = Path.Combine (XABuildPaths.TestOutputDirectory, $"dotnet{DateTime.Now.ToString ("yyyyMMddHHmmssff")}-process.log"); + if (string.IsNullOrEmpty (ProcessLogFile)) { + Directory.CreateDirectory (ProjectDirectory); + ProcessLogFile = Path.Combine (ProjectDirectory, $"dotnet{DateTime.Now.ToString ("yyyyMMddHHmmssff")}-process.log"); + } var procOutput = new StringBuilder (); bool succeeded; @@ -162,9 +157,6 @@ List GetDefaultCommandLineArgs (string verb, string target = null, strin if (!string.IsNullOrEmpty (target)) { arguments.Add ($"/t:{target}"); } - if (project != null) { - arguments.Add ($"/p:Configuration={project.Configuration}"); - } if (Directory.Exists (AndroidSdkPath)) { arguments.Add ($"/p:AndroidSdkDirectory=\"{AndroidSdkPath}\""); } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetStandard.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetStandard.cs index e45acde512a..cc396f31c0f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetStandard.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetStandard.cs @@ -31,20 +31,6 @@ public string PackageTargetFallback { set { SetProperty ("PackageTargetFallback", value); } } - /// - /// Projects targeting net7.0 require ref/runtime packs on NuGet.org or dotnet6/dotnet7 - /// - public void AddNuGetSourcesForOlderTargetFrameworks (string targetFramework = null) - { - targetFramework ??= TargetFramework; - if (targetFramework.IndexOf ("net7.0", StringComparison.OrdinalIgnoreCase) != -1) { - ExtraNuGetConfigSources = new List { - "https://api.nuget.org/v3/index.json", - "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json", - }; - } - } - public string Sdk { get; set; } public IList OtherBuildItems { get; private set; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs index e274ef9f638..346a5dbb71e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs @@ -37,7 +37,7 @@ public abstract class XamarinProject /// /// If true, the ProjectDirectory will be deleted and populated on the first build /// - public virtual bool ShouldPopulate => true; + public virtual bool ShouldPopulate { get; set; } = true; public IList Imports { get; private set; } PropertyGroup common, debug, release; bool isRelease; @@ -418,11 +418,11 @@ public void CopyNuGetConfig (string relativeDirectory) Directory.CreateDirectory (Path.GetDirectoryName (projNugetConfig)); File.Copy (repoNuGetConfig, projNugetConfig, overwrite: true); - var doc = XDocument.Load (projNugetConfig); - AddNuGetConfigSources (doc); + AddNuGetConfigSources (projNugetConfig); // Set a local PackageReference installation folder if specified if (!string.IsNullOrEmpty (GlobalPackagesFolder)) { + var doc = XDocument.Load (projNugetConfig); XElement gpfElement = doc.Descendants ().FirstOrDefault (c => c.Name.LocalName.ToLowerInvariant () == "add" && c.Attributes ().Any (a => a.Name.LocalName.ToLowerInvariant () == "key" && a.Value.ToLowerInvariant () == "globalpackagesfolder")); if (gpfElement != default (XElement)) { @@ -440,35 +440,40 @@ public void CopyNuGetConfig (string relativeDirectory) doc.Root.Add (configParentElement); } } + doc.Save (projNugetConfig); } - - doc.Save (projNugetConfig); } } /// /// Updates a NuGet.config based on sources in ExtraNuGetConfigSources - /// The dotnet7 source is required while in preview, but eventually it should not be needed by tests + /// If target framework is not the latest or default, sources are added for previous releases /// - protected void AddNuGetConfigSources (XDocument doc) + protected void AddNuGetConfigSources (string nugetConfigPath) { + XDocument doc; + if (File.Exists (nugetConfigPath)) + doc = XDocument.Load (nugetConfigPath); + else + doc = new XDocument (new XElement ("configuration")); + const string elementName = "packageSources"; - XElement pkgSourcesElement = doc.Root.Elements ().FirstOrDefault (d => string.Equals (d.Name.LocalName, elementName, StringComparison.OrdinalIgnoreCase)); + XElement pkgSourcesElement = doc.Root?.Elements ().FirstOrDefault (d => string.Equals (d.Name.LocalName, elementName, StringComparison.OrdinalIgnoreCase)); if (pkgSourcesElement == null) { - doc.Root.Add (pkgSourcesElement= new XElement (elementName)); + doc.Root.Add (pkgSourcesElement = new XElement (elementName)); } - foreach (XElement element in pkgSourcesElement.Elements ()) { - XAttribute value = element.Attribute ("value"); - if (value != null && value.Value == "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json") { - element.Remove (); - break; + if (ExtraNuGetConfigSources == null) { + if (TargetFramework?.IndexOf ("net7.0", StringComparison.OrdinalIgnoreCase) != -1) { + ExtraNuGetConfigSources = new List { + "https://api.nuget.org/v3/index.json", + "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json", + }; + } else { + ExtraNuGetConfigSources = new List (); } } - // Add extra sources - if (ExtraNuGetConfigSources == null) - return; int sourceIndex = 0; foreach (var source in ExtraNuGetConfigSources) { var sourceElement = new XElement ("add"); @@ -476,6 +481,8 @@ protected void AddNuGetConfigSources (XDocument doc) sourceElement.SetAttributeValue ("value", source); pkgSourcesElement.Add (sourceElement); } + + doc.Save (nugetConfigPath); } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/ProjectExtensions.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/ProjectExtensions.cs index 87795118382..42473207e1d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/ProjectExtensions.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/ProjectExtensions.cs @@ -9,7 +9,7 @@ public static class ProjectExtensions /// public static void SetAndroidSupportedAbis (this IShortFormProject project, params string [] abis) { - if (Builder.UseDotNet || project is XASdkProject) { + if (Builder.UseDotNet) { project.SetRuntimeIdentifiers (abis); } else { project.SetAndroidSupportedAbis (string.Join (";", abis)); @@ -22,7 +22,7 @@ public static void SetAndroidSupportedAbis (this IShortFormProject project, para /// A semi-colon-delimited list of ABIs public static void SetAndroidSupportedAbis (this IShortFormProject project, string abis) { - if (Builder.UseDotNet || project is XASdkProject) { + if (Builder.UseDotNet) { project.SetRuntimeIdentifiers (abis.Split (';')); } else { project.SetProperty (KnownProperties.AndroidSupportedAbis, abis); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/XmlUtils.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/XmlUtils.cs index 9bf9277eabd..f73aa9ffa5e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/XmlUtils.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/XmlUtils.cs @@ -30,7 +30,7 @@ public static string ToXml (IShortFormProject project) sb.AppendLine ("\t"); } if (project.EnableDefaultItems) { - // If $(EnableDefaultItems), then only OtherBuildItems and References are added + // If $(EnableDefaultItems), then only OtherBuildItems (excluding EmbeddedResource) and References are added if (project.References.Count > 0) { sb.AppendLine ("\t"); foreach (var reference in project.References) { @@ -41,7 +41,9 @@ public static string ToXml (IShortFormProject project) if (project.OtherBuildItems.Count > 0) { sb.AppendLine ("\t"); foreach (var bi in project.OtherBuildItems) { - AppendBuildItem (sb, bi); + if (bi.BuildAction != BuildActions.EmbeddedResource) { + AppendBuildItem (sb, bi); + } } sb.AppendLine ("\t"); } diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 8e8c6b1b360..8e35c576c98 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -718,18 +718,17 @@ bool SeenFailedToLoad (string line) [Test] public void ResourceDesignerWithNuGetReference ([Values ("net8.0-android33.0")] string dotnetTargetFramework) { - string path = Path.Combine (Root, "temp", TestName); - if (!Builder.UseDotNet) { Assert.Ignore ("Skipping. Test not relevant under Classic."); } + // Build a NuGet Package - var nuget = new XASdkProject (outputType: "Library") { + var nuget = new XamarinAndroidLibraryProject () { Sdk = "Xamarin.Legacy.Sdk/0.2.0-alpha4", ProjectName = "Test.Nuget.Package", IsRelease = true, }; - nuget.AddNuGetSourcesForOlderTargetFrameworks (); + nuget.Sources.Clear (); nuget.Sources.Add (new AndroidItem.AndroidResource ("Resources/values/Strings.xml") { TextContent = () => @" @@ -742,9 +741,8 @@ public void ResourceDesignerWithNuGetReference ([Values ("net8.0-android33.0")] nuget.SetProperty ("TargetFramework", value: ""); nuget.SetProperty ("TargetFrameworks", value: $"{dotnetTargetFramework};{legacyTargetFramework}"); - string directory = Path.Combine ("temp", TestName, "Test.Nuget.Package"); - var dotnet = CreateDotNetBuilder (nuget, directory); - Assert.IsTrue (dotnet.Pack (), "`dotnet pack` should succeed"); + var dllBuilder = CreateDllBuilder (); + Assert.IsTrue (dllBuilder.RunTarget (nuget, "Pack"), "`dotnet pack` should succeed"); // Build an app which references it. var proj = new XamarinAndroidApplicationProject () { @@ -755,7 +753,7 @@ public void ResourceDesignerWithNuGetReference ([Values ("net8.0-android33.0")] TextContent = () => @" - + ", }); @@ -763,7 +761,7 @@ public void ResourceDesignerWithNuGetReference ([Values ("net8.0-android33.0")] Id = "Test.Nuget.Package", Version = "1.0.0", }); - builder = CreateApkBuilder (Path.Combine (path, proj.ProjectName)); + builder = CreateApkBuilder (); Assert.IsTrue (builder.Install (proj, doNotCleanupOnUpdate: true), "Install should have succeeded."); string resource_designer = GetResourceDesignerPath (builder, proj); var contents = GetResourceDesignerText (proj, resource_designer); @@ -1017,30 +1015,5 @@ public void CheckResouceIsOverridden ([Values (true, false)] bool useAapt2) } } - - DotNetCLI CreateDotNetBuilder (string relativeProjectDir = null) - { - if (string.IsNullOrEmpty (relativeProjectDir)) { - relativeProjectDir = Path.Combine ("temp", TestName); - } - string fullProjectDirectory = Path.Combine (Root, relativeProjectDir); - TestOutputDirectories [TestContext.CurrentContext.Test.ID] = fullProjectDirectory; - - new XASdkProject ().CopyNuGetConfig (relativeProjectDir); - return new DotNetCLI (Path.Combine (fullProjectDirectory, $"{TestName}.csproj")); - } - - DotNetCLI CreateDotNetBuilder (XASdkProject project, string relativeProjectDir = null) - { - if (string.IsNullOrEmpty (relativeProjectDir)) { - relativeProjectDir = Path.Combine ("temp", TestName); - } - string fullProjectDirectory = Path.Combine (Root, relativeProjectDir); - TestOutputDirectories [TestContext.CurrentContext.Test.ID] = fullProjectDirectory; - var files = project.Save (); - project.Populate (relativeProjectDir, files); - project.CopyNuGetConfig (relativeProjectDir); - return new DotNetCLI (project, Path.Combine (fullProjectDirectory, project.ProjectFilePath)); - } } } diff --git a/tests/MSBuildDeviceIntegration/Tests/XASdkDeployTests.cs b/tests/MSBuildDeviceIntegration/Tests/XASdkDeployTests.cs index 917b668dc79..a40f5d06449 100644 --- a/tests/MSBuildDeviceIntegration/Tests/XASdkDeployTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/XASdkDeployTests.cs @@ -15,6 +15,7 @@ #if !NET472 namespace Xamarin.Android.Build.Tests { + [Obsolete ("De-dupe and migrate these tests to InstallAndRunTests.cs")] [TestFixture] [Category ("UsesDevice"), Category ("WearOS")] public class XASdkDeployTests : DeviceTest @@ -61,42 +62,35 @@ public class XASdkDeployTests : DeviceTest [TestCaseSource (nameof (DotNetInstallAndRunSource))] public void DotNetInstallAndRun (bool isRelease, bool xamarinForms, string targetFramework) { - XASdkProject proj; + XamarinAndroidApplicationProject proj; if (xamarinForms) { - proj = new XamarinFormsXASdkProject { - IsRelease = isRelease + proj = new XamarinFormsAndroidApplicationProject { + IsRelease = isRelease, + EnableDefaultItems = true, }; } else { - proj = new XASdkProject { - IsRelease = isRelease + proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + EnableDefaultItems = true, }; } proj.TargetFramework = targetFramework; - proj.AddNuGetSourcesForOlderTargetFrameworks (); - proj.SetRuntimeIdentifier (DeviceAbi); - - var relativeProjDir = Path.Combine ("temp", TestName); - var fullProjDir = Path.Combine (Root, relativeProjDir); - TestOutputDirectories [TestContext.CurrentContext.Test.ID] = fullProjDir; - var files = proj.Save (); - proj.Populate (relativeProjDir, files); - proj.CopyNuGetConfig (relativeProjDir); - var dotnet = new DotNetCLI (proj, Path.Combine (fullProjDir, proj.ProjectFilePath)); + var builder = CreateApkBuilder (); + Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); + RunProjectAndAssert (proj, builder); - Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); - Assert.IsTrue (dotnet.Run (), "`dotnet run` should succeed"); - WaitForPermissionActivity (Path.Combine (Root, dotnet.ProjectDirectory, "permission-logcat.log")); + WaitForPermissionActivity (Path.Combine (Root, builder.ProjectDirectory, "permission-logcat.log")); bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity", - Path.Combine (fullProjDir, "logcat.log"), 30); - RunAdbCommand ($"uninstall {proj.PackageName}"); + Path.Combine (Root, builder.ProjectDirectory, "logcat.log"), 30); Assert.IsTrue(didLaunch, "Activity should have started."); } [Test] public void TypeAndMemberRemapping ([Values (false, true)] bool isRelease) { - var proj = new XASdkProject () { + var proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, + EnableDefaultItems = true, OtherBuildItems = { new AndroidItem._AndroidRemapMembers ("RemapActivity.xml") { Encoding = Encoding.UTF8, @@ -112,22 +106,13 @@ public void TypeAndMemberRemapping ([Values (false, true)] bool isRelease) }, }; proj.MainActivity = proj.DefaultMainActivity.Replace (": Activity", ": global::Example.RemapActivity"); - proj.SetRuntimeIdentifier (DeviceAbi); - var relativeProjDir = Path.Combine ("temp", TestName); - var fullProjDir = Path.Combine (Root, relativeProjDir); - TestOutputDirectories [TestContext.CurrentContext.Test.ID] = fullProjDir; - var files = proj.Save (); - proj.Populate (relativeProjDir, files); - proj.CopyNuGetConfig (relativeProjDir); - var dotnet = new DotNetCLI (proj, Path.Combine (fullProjDir, proj.ProjectFilePath)); - - Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); - Assert.IsTrue (dotnet.Run (), "`dotnet run` should succeed"); - - bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity", - Path.Combine (fullProjDir, "logcat.log")); + var builder = CreateApkBuilder (); + Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); + RunProjectAndAssert (proj, builder); + var appStartupLogcatFile = Path.Combine (Root, builder.ProjectDirectory, "logcat.log"); + bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity", appStartupLogcatFile); Assert.IsTrue (didLaunch, "MainActivity should have launched!"); - var logcatOutput = File.ReadAllText (Path.Combine (fullProjDir, "logcat.log")); + var logcatOutput = File.ReadAllText (appStartupLogcatFile); StringAssert.Contains ( "RemapActivity.onMyCreate() invoked!", @@ -144,13 +129,9 @@ public void TypeAndMemberRemapping ([Values (false, true)] bool isRelease) [Test] public void SupportDesugaringStaticInterfaceMethods () { - AssertHasDevices (); - if (!Builder.UseDotNet) { - Assert.Ignore ("Skipping. Test not relevant under Classic."); - } - - var proj = new XASdkProject () { + var proj = new XamarinAndroidApplicationProject () { IsRelease = true, + EnableDefaultItems = true, OtherBuildItems = { new AndroidItem.AndroidJavaSource ("StaticMethodsInterface.java") { Encoding = new UTF8Encoding (encoderShouldEmitUTF8Identifier: false), @@ -165,27 +146,18 @@ public void SupportDesugaringStaticInterfaceMethods () // Note: To properly test, Desugaring must be *enabled*, which requires that // `$(SupportedOSPlatformVersion)` be *less than* 23. 21 is currently the default, // but set this explicitly anyway just so that this implicit requirement is explicit. - proj.SetProperty (proj.ReleaseProperties, "SupportedOSPlatformVersion", "21"); + proj.SupportedOSPlatformVersion = "21"; proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", @" Console.WriteLine ($""# jonp static interface default method invocation; IStaticMethodsInterface.Value={Example.IStaticMethodsInterface.Value}""); "); - proj.SetRuntimeIdentifier (DeviceAbi); - var relativeProjDir = Path.Combine ("temp", TestName); - var fullProjDir = Path.Combine (Root, relativeProjDir); - TestOutputDirectories [TestContext.CurrentContext.Test.ID] = fullProjDir; - var files = proj.Save (); - proj.Populate (relativeProjDir, files); - proj.CopyNuGetConfig (relativeProjDir); - var dotnet = new DotNetCLI (proj, Path.Combine (fullProjDir, proj.ProjectFilePath)); - - Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); - Assert.IsTrue (dotnet.Run (), "`dotnet run` should succeed"); - - bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity", - Path.Combine (fullProjDir, "logcat.log")); + var builder = CreateApkBuilder (); + Assert.IsTrue (builder.Build (proj), "`dotnet build` should succeed"); + RunProjectAndAssert (proj, builder); + var appStartupLogcatFile = Path.Combine (Root, builder.ProjectDirectory, "logcat.log"); + bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity", appStartupLogcatFile); Assert.IsTrue (didLaunch, "MainActivity should have launched!"); - var logcatOutput = File.ReadAllText (Path.Combine (fullProjDir, "logcat.log")); + var logcatOutput = File.ReadAllText (appStartupLogcatFile); StringAssert.Contains ( "IStaticMethodsInterface.Value=3", @@ -201,20 +173,17 @@ public void DotNetDebug ([Values("net7.0-android", "net8.0-android")] string tar { AssertCommercialBuild (); - var proj = new XASdkProject (); + var proj = new XamarinAndroidApplicationProject () { + EnableDefaultItems = true, + }; proj.TargetFramework = targetFramework; - proj.AddNuGetSourcesForOlderTargetFrameworks (); + proj.EnableDefaultItems = true; proj.SetRuntimeIdentifier (DeviceAbi); string runtimeId = proj.GetProperty (KnownProperties.RuntimeIdentifier); - var relativeProjDir = Path.Combine ("temp", TestName); - var fullProjDir = Path.Combine (Root, relativeProjDir); - TestOutputDirectories [TestContext.CurrentContext.Test.ID] = fullProjDir; - var files = proj.Save (); - proj.Populate (relativeProjDir, files); - proj.CopyNuGetConfig (relativeProjDir); - var dotnet = new DotNetCLI (proj, Path.Combine (fullProjDir, proj.ProjectFilePath)); - Assert.IsTrue (dotnet.Build ("Install"), "`dotnet build` should succeed"); + var builder = CreateApkBuilder (); + + Assert.IsTrue (builder.Install (proj), "Install should succeed."); bool breakpointHit = false; ManualResetEvent resetEvent = new ManualResetEvent (false); @@ -223,7 +192,7 @@ public void DotNetDebug ([Values("net7.0-android", "net8.0-android")] string tar var session = new SoftDebuggerSession (); try { session.Breakpoints = new BreakpointStore { - { Path.Combine (Root, dotnet.ProjectDirectory, "MainActivity.cs"), 10 }, + { Path.Combine (Root, builder.ProjectDirectory, "MainActivity.cs"), 10 }, }; session.TargetHitBreakpoint += (sender, e) => { Console.WriteLine ($"BREAK {e.Type}"); @@ -237,20 +206,20 @@ public void DotNetDebug ([Values("net7.0-android", "net8.0-android")] string tar MaxConnectionAttempts = 10, }; var startInfo = new SoftDebuggerStartInfo (args) { - WorkingDirectory = Path.Combine (dotnet.ProjectDirectory, proj.IntermediateOutputPath, runtimeId, "android", "assets"), + WorkingDirectory = Path.Combine (builder.ProjectDirectory, proj.IntermediateOutputPath, runtimeId, "android", "assets"), }; var options = new DebuggerSessionOptions () { EvaluationOptions = EvaluationOptions.DefaultOptions, }; options.EvaluationOptions.UseExternalTypeResolver = true; - dotnet.BuildLogFile = Path.Combine (Root, dotnet.ProjectDirectory, "run.log"); - Assert.True (dotnet.Build ("Run", parameters: new [] { + builder.BuildLogFile = Path.Combine (Root, builder.ProjectDirectory, "run.log"); + Assert.True (builder.RunTarget (proj, "Run", parameters: new [] { $"AndroidSdbTargetPort={port}", $"AndroidSdbHostPort={port}", "AndroidAttachDebugger=True", }), "Project should have run."); - WaitForPermissionActivity (Path.Combine (Root, dotnet.ProjectDirectory, "permission-logcat.log")); - Assert.IsTrue (WaitForDebuggerToStart (Path.Combine (Root, dotnet.ProjectDirectory, "logcat.log"), 120), "Activity should have started"); + WaitForPermissionActivity (Path.Combine (Root, builder.ProjectDirectory, "permission-logcat.log")); + Assert.IsTrue (WaitForDebuggerToStart (Path.Combine (Root, builder.ProjectDirectory, "logcat.log"), 120), "Activity should have started"); // we need to give a bit of time for the debug server to start up. WaitFor (2000); session.LogWriter += (isStderr, text) => { Console.WriteLine (text); };