public void AppBundleSigned () { var aab = Path.Combine (bin, "UnnamedProject.UnnamedProject-Signed.aab"); FileAssert.Exists (aab); var contents = ListArchiveContents (aab); Assert.IsTrue (StringAssertEx.ContainsText (contents, "META-INF/MANIFEST.MF"), $"{aab} is not signed!"); }
public void InstallErrorCode() { AssertCommercialBuild(); AssertHasDevices(); //Setup a situation where we get INSTALL_FAILED_NO_MATCHING_ABIS var abi = "armeabi-v7a"; var proj = new XamarinAndroidApplicationProject { EmbedAssembliesIntoApk = true, }; proj.SetAndroidSupportedAbis(abi); using (var builder = CreateApkBuilder(Path.Combine("temp", TestContext.CurrentContext.Test.Name))) { builder.ThrowOnBuildFailure = false; if (!builder.Install(proj)) { Assert.IsTrue(StringAssertEx.ContainsText(builder.LastBuildOutput, "ADB0020"), "Should receive ADB0020 error code."); } else { Assert.Ignore($"Install should have failed, but we might have an {abi} emulator attached."); } } }
public void InstallErrorCode() { if (!CommercialBuildAvailable) { Assert.Ignore("Not required on Open Source Builds"); } if (!HasDevices) { Assert.Ignore("Test Skipped no devices or emulators found."); } //Setup a situation where we get INSTALL_FAILED_NO_MATCHING_ABIS var abi = "armeabi-v7a"; var proj = new XamarinAndroidApplicationProject { AndroidUseSharedRuntime = false, EmbedAssembliesIntoApk = true, }; proj.SetProperty(proj.DebugProperties, KnownProperties.AndroidSupportedAbis, abi); using (var builder = CreateApkBuilder(Path.Combine("temp", TestContext.CurrentContext.Test.Name))) { builder.ThrowOnBuildFailure = false; if (!builder.Install(proj)) { Assert.IsTrue(StringAssertEx.ContainsText(builder.LastBuildOutput, "ADB0020"), "Should receive ADB0020 error code."); } else { Assert.Ignore($"Install should have failed, but we might have an {abi} emulator attached."); } } }
public void BuildBasicBindingLibrary(string classParser) { var proj = new XamarinAndroidBindingProject() { IsRelease = true, }; proj.Jars.Add(new AndroidItem.EmbeddedJar("Jars\\svg-android.jar") { WebContent = "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/svg-android/svg-android.jar" }); proj.AndroidClassParser = classParser; using (var b = CreateDllBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); //A list of properties we check exist in binding projects var properties = new [] { "AndroidSdkBuildToolsVersion", "AndroidSdkPlatformToolsVersion", "AndroidSdkToolsVersion", "AndroidNdkVersion", }; foreach (var property in properties) { Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, property + " = "), $"$({property}) should be set!"); } } }
public void BuildBasicBindingLibrary(string classParser) { var targets = new List <string> { "_ExportJarToXml", "GenerateBindings", "_ResolveLibraryProjectImports", "CoreCompile", }; if (Builder.UseDotNet) { targets.Add("_CreateAar"); } else { targets.Add("_CreateBindingResourceArchive"); //TODO: .NET 5+ cannot support javadoc yet, due to missing mdoc targets.Add("_ExtractJavaDocJars"); targets.Add("BuildDocumentation"); } var proj = new XamarinAndroidBindingProject() { IsRelease = true, }; proj.Jars.Add(new AndroidItem.AndroidLibrary("Jars\\svg-android.jar") { WebContent = "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/svg-android/svg-android.jar" }); proj.AndroidClassParser = classParser; using (var b = CreateDllBuilder()) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); var assemblyPath = Path.Combine(Root, b.ProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll"); using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath)) { var typeName = "Com.Larvalabs.Svgandroid.SVG"; var type = assembly.MainModule.GetType(typeName); Assert.IsNotNull(type, $"{assemblyPath} should contain {typeName}"); } //A list of properties we check exist in binding projects var properties = new [] { "AndroidSdkBuildToolsVersion", "AndroidSdkPlatformToolsVersion", "AndroidSdkToolsVersion", "AndroidNdkVersion", }; foreach (var property in properties) { Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, property + " = "), $"$({property}) should be set!"); } Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "second build should succeed"); foreach (var target in targets) { Assert.IsTrue(b.Output.IsTargetSkipped(target), $"`{target}` should be skipped on second build!"); } } }
public void CheckSignApk([Values(true, false)] bool useApkSigner, [Values(true, false)] bool perAbiApk) { string ext = Environment.OSVersion.Platform != PlatformID.Unix ? ".bat" : ""; var foundApkSigner = Directory.EnumerateDirectories(Path.Combine(AndroidSdkPath, "build-tools")).Any(dir => Directory.EnumerateFiles(dir, "apksigner" + ext).Any()); if (useApkSigner && !foundApkSigner) { Assert.Ignore("Skipping test. Required build-tools verison which contains apksigner is not installed."); } var proj = new XamarinAndroidApplicationProject() { IsRelease = true, }; if (useApkSigner) { proj.SetProperty("AndroidUseApkSigner", "true"); } else { proj.RemoveProperty("AndroidUseApkSigner"); } proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, perAbiApk); proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidSupportedAbis, "armeabi-v7a;x86"); using (var b = CreateApkBuilder(Path.Combine("temp", TestContext.CurrentContext.Test.Name))) { b.Verbosity = Microsoft.Build.Framework.LoggerVerbosity.Diagnostic; Assert.IsTrue(b.Build(proj), "build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)")); proj.AndroidResources.First().Timestamp = null; Assert.IsTrue(b.Build(proj), "Second build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)")); } }
public void DotNetBuildXamarinForms() { var proj = new XamarinFormsXASdkProject(); var dotnet = CreateDotNetBuilder(proj); Assert.IsTrue(dotnet.Build(), "`dotnet build` should succeed"); Assert.IsTrue(StringAssertEx.ContainsText(dotnet.LastBuildOutput, " 0 Warning(s)"), "Should have no MSBuild warnings."); }
public void CheckSignApk([Values(true, false)] bool useApkSigner, [Values(true, false)] bool perAbiApk) { string ext = Environment.OSVersion.Platform != PlatformID.Unix ? ".bat" : ""; var foundApkSigner = Directory.EnumerateDirectories(Path.Combine(AndroidSdkPath, "build-tools")).Any(dir => Directory.EnumerateFiles(dir, "apksigner" + ext).Any()); if (useApkSigner && !foundApkSigner) { Assert.Ignore("Skipping test. Required build-tools verison which contains apksigner is not installed."); } var proj = new XamarinAndroidApplicationProject() { IsRelease = true, }; if (useApkSigner) { proj.SetProperty("AndroidUseApkSigner", "true"); } else { proj.RemoveProperty("AndroidUseApkSigner"); } proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, perAbiApk); proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidSupportedAbis, "armeabi-v7a;x86"); using (var b = CreateApkBuilder(Path.Combine("temp", TestContext.CurrentContext.Test.Name))) { var bin = Path.Combine(Root, b.ProjectDirectory, proj.OutputPath); Assert.IsTrue(b.Build(proj), "First build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)"), "First build should not contain warnings! Contains\n" + string.Join("\n", b.LastBuildOutput.Where(line => line.Contains("warning")))); //Make sure the APKs are signed foreach (var apk in Directory.GetFiles(bin, "*-Signed.apk")) { using (var zip = ZipHelper.OpenZip(apk)) { Assert.IsTrue(zip.Any(e => e.FullName == "META-INF/MANIFEST.MF"), $"APK file `{apk}` is not signed! It is missing `META-INF/MANIFEST.MF`."); } } var item = proj.AndroidResources.First(x => x.Include() == "Resources\\values\\Strings.xml"); item.TextContent = () => proj.StringsXml.Replace("${PROJECT_NAME}", "Foo"); item.Timestamp = null; Assert.IsTrue(b.Build(proj), "Second build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)"), "Second build should not contain warnings! Contains\n" + string.Join("\n", b.LastBuildOutput.Where(line => line.Contains("warning")))); //Make sure the APKs are signed foreach (var apk in Directory.GetFiles(bin, "*-Signed.apk")) { using (var zip = ZipHelper.OpenZip(apk)) { Assert.IsTrue(zip.Any(e => e.FullName == "META-INF/MANIFEST.MF"), $"APK file `{apk}` is not signed! It is missing `META-INF/MANIFEST.MF`."); } } } }
void WarnAboutAppDomains(XamarinAndroidApplicationProject proj, string testName) { proj.MainActivity = proj.DefaultMainActivity.Replace("base.OnCreate (bundle);", "base.OnCreate (bundle);\nvar appDomain = System.AppDomain.CreateDomain (\"myDomain\");"); var projDirectory = Path.Combine("temp", testName); using (var b = CreateApkBuilder(projDirectory)) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "Warning: Use of AppDomain::CreateDomain"), "Should warn about creating AppDomain."); } }
public void Aapt2Disabled() { var proj = new XamarinAndroidApplicationProject(); proj.SetProperty("AndroidUseAapt2", "False"); using (var b = CreateApkBuilder("temp/Aapt2Disabled")) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "Task \"Aapt2Link\" skipped"), "Aapt2Link task should be skipped!"); Assert.IsTrue(b.Output.IsTargetSkipped("_CreateAapt2VersionCache"), "_CreateAapt2VersionCache target should be skipped!"); } }
void WarnAboutAppDomains(XamarinAndroidApplicationProject proj, string testName) { proj.MainActivity = proj.DefaultMainActivity.Replace("base.OnCreate (bundle);", "base.OnCreate (bundle);\nvar appDomain = System.AppDomain.CreateDomain (\"myDomain\");"); var projDirectory = Path.Combine("temp", testName); using (var b = CreateApkBuilder(projDirectory)) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "2 Warning(s)"), "MSBuild should count 2 warnings."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "warning CS0618: 'AppDomain.CreateDomain(string)' is obsolete: 'AppDomain.CreateDomain will no longer be supported in .NET 5 and later."), "Should warn CS0618 about creating AppDomain."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "warning XA2000: Use of AppDomain.CreateDomain()"), "Should warn XA2000 about creating AppDomain."); } }
public void Edge(int limit, bool xamarinForms) { var testName = $"{nameof (Edge)}{xamarinForms}" .PadRight(Files.MaxPath - BaseLength - limit, 'N'); var proj = CreateProject(xamarinForms); using (var b = CreateApkBuilder(Path.Combine("temp", testName))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(b.Clean(proj), "Clean should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, $"Trying long path: {Files.LongPathPrefix}"), "A long path should be encountered."); } }
public void Aapt2Disabled() { AssertAaptSupported(useAapt2: false); var proj = new XamarinAndroidApplicationProject(); proj.AndroidUseAapt2 = false; using (var b = CreateApkBuilder()) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsFalse(StringAssertEx.ContainsText(b.LastBuildOutput, "Aapt2Link"), "Aapt2Link task should not run!"); Assert.IsFalse(StringAssertEx.ContainsText(b.LastBuildOutput, "Aapt2Compile"), "Aapt2Compile task should not run!"); Assert.IsFalse(StringAssertEx.ContainsText(b.LastBuildOutput, "_CreateAapt2VersionCache"), "_CreateAapt2VersionCache target should not run!"); } }
public void LongPath() { if (!IsWindows) { Assert.Ignore("MAX_PATH only applies on Windows"); } var file = NewFile(fileName: "foo".PadRight(250, 'N')); var task = CreateTask(); Assert.IsTrue(task.Execute(), "task.Execute() should have succeeded."); Assert.AreEqual(1, task.RemovedDirectories.Length, "Changes should have been made."); DirectoryAssert.DoesNotExist(tempDirectory); Assert.IsTrue(StringAssertEx.ContainsText(messages.Select(m => m.Message), $"Trying long path: {Files.LongPathPrefix}"), "A long path should be encountered."); }
public void OverTheEdge(int limit, bool xamarinForms) { var testName = $"{nameof (Edge)}{xamarinForms}" .PadRight(Files.MaxPath - BaseLength - limit, 'N'); var proj = CreateProject(xamarinForms); using (var b = CreateApkBuilder(Path.Combine("temp", testName))) { b.ThrowOnBuildFailure = false; Assert.IsFalse(b.Build(proj), "Build should have failed."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "XA5301"), "Should get MAX_PATH warning"); b.ThrowOnBuildFailure = true; Assert.IsTrue(b.Clean(proj), "Clean should have succeeded."); } }
public void LongPath() { if (LongPathsSupported) { Assert.Ignore("This environment supports long paths"); } var file = NewFile(fileName: "foo".PadRight(MaxFileName, 'N')); var task = CreateTask(); Assert.IsTrue(task.Execute(), "task.Execute() should have succeeded."); Assert.AreEqual(1, task.RemovedDirectories.Length, "Changes should have been made."); DirectoryAssert.DoesNotExist(tempDirectory); Assert.IsTrue(StringAssertEx.ContainsText(messages.Select(m => m.Message), $"Trying long path: {Files.LongPathPrefix}"), "A long path should be encountered."); }
public void BuildBasicBindingLibrary(string classParser) { var targets = new List <string> { "_ExportJarToXml", "GenerateBindings", "_CreateBindingResourceArchive", "_ResolveLibraryProjectImports", "CoreCompile", }; if (!Builder.UseDotNet) { //TODO: .NET 5+ cannot support javadoc yet, due to missing mdoc targets.Add("_ExtractJavaDocJars"); targets.Add("BuildDocumentation"); } var proj = new XamarinAndroidBindingProject() { IsRelease = true, }; proj.Jars.Add(new AndroidItem.EmbeddedJar("Jars\\svg-android.jar") { WebContent = "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/svg-android/svg-android.jar" }); proj.AndroidClassParser = classParser; using (var b = CreateDllBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); //A list of properties we check exist in binding projects var properties = new [] { "AndroidSdkBuildToolsVersion", "AndroidSdkPlatformToolsVersion", "AndroidSdkToolsVersion", "AndroidNdkVersion", }; foreach (var property in properties) { Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, property + " = "), $"$({property}) should be set!"); } Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "second build should succeed"); foreach (var target in targets) { Assert.IsTrue(b.Output.IsTargetSkipped(target), $"`{target}` should be skipped on second build!"); } } }
[Category("DotNetIgnore")] // n/a on .NET 5+ public void WarnAboutAppDomains([Values(true, false)] bool isRelease) { var proj = new XamarinAndroidApplicationProject() { IsRelease = isRelease }; proj.MainActivity = proj.DefaultMainActivity.Replace("base.OnCreate (bundle);", "base.OnCreate (bundle);\nvar appDomain = System.AppDomain.CreateDomain (\"myDomain\");"); using (var b = CreateApkBuilder()) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "2 Warning(s)"), "MSBuild should count 2 warnings."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "warning CS0618: 'AppDomain.CreateDomain(string)' is obsolete: 'AppDomain.CreateDomain will no longer be supported in .NET 5 and later."), "Should warn CS0618 about creating AppDomain."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "warning XA2000: Use of AppDomain.CreateDomain()"), "Should warn XA2000 about creating AppDomain."); } }
public void DotNetBuild(string runtimeIdentifier, bool isRelease) { var abi = MonoAndroidHelper.RuntimeIdentifierToAbi(runtimeIdentifier); var proj = new XASdkProject { IsRelease = isRelease }; proj.OtherBuildItems.Add(new AndroidItem.InputJar("javaclasses.jar") { BinaryContent = () => Convert.FromBase64String(InlineData.JavaClassesJarBase64) }); // TODO: bring back when Xamarin.Android.Bindings.Documentation.targets is working //proj.OtherBuildItems.Add (new BuildItem ("JavaSourceJar", "javasources.jar") { // BinaryContent = () => Convert.FromBase64String (InlineData.JavaSourcesJarBase64) //}); proj.SetProperty(KnownProperties.RuntimeIdentifier, runtimeIdentifier); var dotnet = CreateDotNetBuilder(proj); Assert.IsTrue(dotnet.Build(), "`dotnet build` should succeed"); // TODO: run for release once illink warnings are gone // context: https://github.com/xamarin/xamarin-android/issues/4708 if (!isRelease) { Assert.IsTrue(StringAssertEx.ContainsText(dotnet.LastBuildOutput, " 0 Warning(s)"), "Should have no MSBuild warnings."); } var outputPath = Path.Combine(Root, dotnet.ProjectDirectory, proj.OutputPath, runtimeIdentifier); var assemblyPath = Path.Combine(outputPath, "UnnamedProject.dll"); FileAssert.Exists(assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath)) { var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest"; var type = assembly.MainModule.GetType(typeName); Assert.IsNotNull(type, $"{assemblyPath} should contain {typeName}"); } var apk = Path.Combine(outputPath, "UnnamedProject.UnnamedProject.apk"); FileAssert.Exists(apk); using (var zip = ZipHelper.OpenZip(apk)) { Assert.IsTrue(zip.ContainsEntry($"lib/{abi}/libmonodroid.so"), "libmonodroid.so should exist."); Assert.IsTrue(zip.ContainsEntry($"lib/{abi}/libmonosgen-2.0.so"), "libmonosgen-2.0.so should exist."); } }
public void DotNetBuild(string runtimeIdentifiers, bool isRelease) { var proj = new XASdkProject { IsRelease = isRelease }; proj.OtherBuildItems.Add(new AndroidItem.InputJar("javaclasses.jar") { BinaryContent = () => Convert.FromBase64String(InlineData.JavaClassesJarBase64) }); // TODO: bring back when Xamarin.Android.Bindings.Documentation.targets is working //proj.OtherBuildItems.Add (new BuildItem ("JavaSourceJar", "javasources.jar") { // BinaryContent = () => Convert.FromBase64String (InlineData.JavaSourcesJarBase64) //}); if (!runtimeIdentifiers.Contains(";")) { proj.SetProperty(KnownProperties.RuntimeIdentifier, runtimeIdentifiers); } else { proj.SetProperty(KnownProperties.RuntimeIdentifiers, runtimeIdentifiers); } var dotnet = CreateDotNetBuilder(proj); Assert.IsTrue(dotnet.Build(), "`dotnet build` should succeed"); // TODO: run for release once illink warnings are gone // context: https://github.com/xamarin/xamarin-android/issues/4708 if (!isRelease) { Assert.IsTrue(StringAssertEx.ContainsText(dotnet.LastBuildOutput, " 0 Warning(s)"), "Should have no MSBuild warnings."); } var outputPath = Path.Combine(FullProjectDirectory, proj.OutputPath); if (!runtimeIdentifiers.Contains(";")) { outputPath = Path.Combine(outputPath, runtimeIdentifiers); } // TODO: With workloads we don't control the import of Microsoft.NET.Sdk/Sdk.targets. // We can no longer change the default values of `$(GenerateDependencyFile)` and `$(ProduceReferenceAssembly)` as a result. // We should update Microsoft.NET.Sdk to default both of these properties to false when the `$(TargetPlatformIdentifier)` is "mobile" (Android, iOS, etc). // Alternatively, the workload concept could be updated to support some sort of `Before.Microsoft.NET.targets` hook. /* var files = Directory.EnumerateFileSystemEntries (outputPath) * .Select (Path.GetFileName) * .OrderBy (f => f); * CollectionAssert.AreEqual (new [] { * $"{proj.ProjectName}.dll", * $"{proj.ProjectName}.pdb", * $"{proj.PackageName}.apk", * $"{proj.PackageName}-Signed.apk", * }, files); */ var assemblyPath = Path.Combine(outputPath, $"{proj.ProjectName}.dll"); FileAssert.Exists(assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath)) { var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest"; var type = assembly.MainModule.GetType(typeName); Assert.IsNotNull(type, $"{assemblyPath} should contain {typeName}"); } bool expectEmbeddedAssembies = !(CommercialBuildAvailable && !isRelease); var apkPath = Path.Combine(outputPath, "UnnamedProject.UnnamedProject.apk"); FileAssert.Exists(apkPath); using (var apk = ZipHelper.OpenZip(apkPath)) { var rids = runtimeIdentifiers.Split(';'); foreach (var abi in rids.Select(MonoAndroidHelper.RuntimeIdentifierToAbi)) { apk.AssertContainsEntry(apkPath, $"lib/{abi}/libmonodroid.so"); apk.AssertContainsEntry(apkPath, $"lib/{abi}/libmonosgen-2.0.so"); if (rids.Length > 1) { apk.AssertContainsEntry(apkPath, $"assemblies/{abi}/System.Private.CoreLib.dll", expectEmbeddedAssembies); } else { apk.AssertContainsEntry(apkPath, "assemblies/System.Private.CoreLib.dll", expectEmbeddedAssembies); } } } }
public void DotNetBuild(string runtimeIdentifiers, bool isRelease) { var proj = new XASdkProject { IsRelease = isRelease }; proj.OtherBuildItems.Add(new AndroidItem.InputJar("javaclasses.jar") { BinaryContent = () => Convert.FromBase64String(InlineData.JavaClassesJarBase64) }); // TODO: bring back when Xamarin.Android.Bindings.Documentation.targets is working //proj.OtherBuildItems.Add (new BuildItem ("JavaSourceJar", "javasources.jar") { // BinaryContent = () => Convert.FromBase64String (InlineData.JavaSourcesJarBase64) //}); if (!runtimeIdentifiers.Contains(";")) { proj.SetProperty(KnownProperties.RuntimeIdentifier, runtimeIdentifiers); } else { proj.SetProperty(KnownProperties.RuntimeIdentifiers, runtimeIdentifiers); } var dotnet = CreateDotNetBuilder(proj); Assert.IsTrue(dotnet.Build(), "`dotnet build` should succeed"); // TODO: run for release once illink warnings are gone // context: https://github.com/xamarin/xamarin-android/issues/4708 if (!isRelease) { Assert.IsTrue(StringAssertEx.ContainsText(dotnet.LastBuildOutput, " 0 Warning(s)"), "Should have no MSBuild warnings."); } var outputPath = Path.Combine(FullProjectDirectory, proj.OutputPath); if (!runtimeIdentifiers.Contains(";")) { outputPath = Path.Combine(outputPath, runtimeIdentifiers); } var files = Directory.EnumerateFileSystemEntries(outputPath) .Select(Path.GetFileName) .OrderBy(f => f) .ToArray(); CollectionAssert.AreEqual(new [] { $"{proj.ProjectName}.dll", $"{proj.ProjectName}.pdb", $"{proj.PackageName}.apk", $"{proj.PackageName}-Signed.apk", }, files); var assemblyPath = Path.Combine(outputPath, $"{proj.ProjectName}.dll"); FileAssert.Exists(assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath)) { var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest"; var type = assembly.MainModule.GetType(typeName); Assert.IsNotNull(type, $"{assemblyPath} should contain {typeName}"); } bool expectEmbeddedAssembies = !(CommercialBuildAvailable && !isRelease); var apkPath = Path.Combine(outputPath, "UnnamedProject.UnnamedProject.apk"); FileAssert.Exists(apkPath); using (var apk = ZipHelper.OpenZip(apkPath)) { apk.AssertContainsEntry(apkPath, $"assemblies/{proj.ProjectName}.dll", shouldContainEntry: expectEmbeddedAssembies); apk.AssertContainsEntry(apkPath, $"assemblies/{proj.ProjectName}.pdb", shouldContainEntry: !CommercialBuildAvailable && !isRelease); apk.AssertContainsEntry(apkPath, $"assemblies/System.Linq.dll", shouldContainEntry: expectEmbeddedAssembies); var rids = runtimeIdentifiers.Split(';'); foreach (var abi in rids.Select(MonoAndroidHelper.RuntimeIdentifierToAbi)) { apk.AssertContainsEntry(apkPath, $"lib/{abi}/libmonodroid.so"); apk.AssertContainsEntry(apkPath, $"lib/{abi}/libmonosgen-2.0.so"); if (rids.Length > 1) { apk.AssertContainsEntry(apkPath, $"assemblies/{abi}/System.Private.CoreLib.dll", shouldContainEntry: expectEmbeddedAssembies); apk.AssertContainsEntry(apkPath, $"assemblies/{abi}/System.Collections.Concurrent.dll", shouldContainEntry: expectEmbeddedAssembies); } else { apk.AssertContainsEntry(apkPath, "assemblies/System.Private.CoreLib.dll", shouldContainEntry: expectEmbeddedAssembies); apk.AssertContainsEntry(apkPath, "assemblies/System.Collections.Concurrent.dll", shouldContainEntry: expectEmbeddedAssembies); } } } }
public void BuildApplicationWithMonoEnvironment([Values("", "Normal", "Offline")] string sequencePointsMode) { const string supportedAbis = "armeabi-v7a;x86"; var lib = new XamarinAndroidLibraryProject { ProjectName = "Library1", IsRelease = true, OtherBuildItems = { new AndroidItem.AndroidEnvironment("Mono.env") { TextContent = () => "MONO_DEBUG=soft-breakpoints" }, }, }; var app = new XamarinFormsAndroidApplicationProject() { IsRelease = true, AndroidLinkModeRelease = AndroidLinkMode.Full, References = { new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj"), }, }; //LinkSkip one assembly that contains __AndroidLibraryProjects__.zip string linkSkip = "FormsViewGroup"; app.SetProperty("AndroidLinkSkip", linkSkip); app.SetProperty("_AndroidSequencePointsMode", sequencePointsMode); app.SetAndroidSupportedAbis(supportedAbis); using (var libb = CreateDllBuilder(Path.Combine("temp", TestName, lib.ProjectName))) using (var appb = CreateApkBuilder(Path.Combine("temp", TestName, app.ProjectName))) { Assert.IsTrue(libb.Build(lib), "Library build should have succeeded."); Assert.IsTrue(appb.Build(app), "App should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(appb.LastBuildOutput, $"Save assembly: {linkSkip}"), $"{linkSkip} should be saved, and not linked!"); string intermediateOutputDir = Path.Combine(Root, appb.ProjectDirectory, app.IntermediateOutputPath); List <string> envFiles = EnvironmentHelper.GatherEnvironmentFiles(intermediateOutputDir, supportedAbis, true); Dictionary <string, string> envvars = EnvironmentHelper.ReadEnvironmentVariables(envFiles); Assert.IsTrue(envvars.Count > 0, $"No environment variables defined"); string monoDebugVar; Assert.IsTrue(envvars.TryGetValue("MONO_DEBUG", out monoDebugVar), "Environment should contain MONO_DEBUG"); Assert.IsFalse(String.IsNullOrEmpty(monoDebugVar), "Environment must contain MONO_DEBUG with a value"); Assert.IsTrue(monoDebugVar.IndexOf("soft-breakpoints") >= 0, "Environment must contain MONO_DEBUG with 'soft-breakpoints' in its value"); if (!String.IsNullOrEmpty(sequencePointsMode)) { Assert.IsTrue(monoDebugVar.IndexOf("gen-compact-seq-points") >= 0, "The values from Mono.env should have been merged into environment"); } EnvironmentHelper.AssertValidEnvironmentSharedLibrary(intermediateOutputDir, AndroidSdkPath, AndroidNdkPath, supportedAbis); var assemblyDir = Path.Combine(Root, appb.ProjectDirectory, app.IntermediateOutputPath, "android", "assets"); var rp = new ReaderParameters { ReadSymbols = false }; foreach (var assemblyFile in Directory.EnumerateFiles(assemblyDir, "*.dll")) { using (var assembly = AssemblyDefinition.ReadAssembly(assemblyFile)) { foreach (var module in assembly.Modules) { var resources = module.Resources.Select(r => r.Name).ToArray(); Assert.IsFalse(StringAssertEx.ContainsText(resources, "__AndroidEnvironment__"), "AndroidEnvironment EmbeddedResource should be stripped!"); Assert.IsFalse(StringAssertEx.ContainsText(resources, "__AndroidLibraryProjects__.zip"), "__AndroidLibraryProjects__.zip should be stripped!"); Assert.IsFalse(StringAssertEx.ContainsText(resources, "__AndroidNativeLibraries__.zip"), "__AndroidNativeLibraries__.zip should be stripped!"); } } } } }
public void DotNetBuild(string runtimeIdentifiers, bool isRelease) { var proj = new XASdkProject { IsRelease = isRelease, ExtraNuGetConfigSources = { "https://pkgs.dev.azure.com/azure-public/vside/_packaging/xamarin-impl/nuget/v3/index.json" }, PackageReferences = { new Package { Id = "Xamarin.AndroidX.AppCompat", Version = "1.2.0.7-net6preview01" } }, Sources = { new BuildItem("EmbeddedResource", "Foo.resx") { TextContent = () => InlineData.ResxWithContents("<data name=\"CancelButton\"><value>Cancel</value></data>") }, new BuildItem("EmbeddedResource", "Foo.es.resx") { TextContent = () => InlineData.ResxWithContents("<data name=\"CancelButton\"><value>Cancelar</value></data>") }, } }; proj.MainActivity = proj.DefaultMainActivity.Replace(": Activity", ": AndroidX.AppCompat.App.AppCompatActivity"); proj.OtherBuildItems.Add(new AndroidItem.InputJar("javaclasses.jar") { BinaryContent = () => ResourceData.JavaSourceJarTestJar, }); proj.OtherBuildItems.Add(new BuildItem("JavaSourceJar", "javaclasses-sources.jar") { BinaryContent = () => ResourceData.JavaSourceJarTestSourcesJar, }); if (!runtimeIdentifiers.Contains(";")) { proj.SetProperty(KnownProperties.RuntimeIdentifier, runtimeIdentifiers); } else { proj.SetProperty(KnownProperties.RuntimeIdentifiers, runtimeIdentifiers); } var dotnet = CreateDotNetBuilder(proj); Assert.IsTrue(dotnet.Build(), "`dotnet build` should succeed"); Assert.IsTrue(StringAssertEx.ContainsText(dotnet.LastBuildOutput, " 0 Warning(s)"), "Should have no MSBuild warnings."); var outputPath = Path.Combine(FullProjectDirectory, proj.OutputPath); var intermediateOutputPath = Path.Combine(FullProjectDirectory, proj.IntermediateOutputPath); if (!runtimeIdentifiers.Contains(";")) { outputPath = Path.Combine(outputPath, runtimeIdentifiers); intermediateOutputPath = Path.Combine(intermediateOutputPath, runtimeIdentifiers); } var files = Directory.EnumerateFileSystemEntries(outputPath) .Select(Path.GetFileName) .OrderBy(f => f) .ToArray(); var expectedFiles = new[] { $"{proj.PackageName}.apk", $"{proj.PackageName}-Signed.apk", "es", $"{proj.ProjectName}.dll", $"{proj.ProjectName}.pdb", $"{proj.ProjectName}.xml", }; CollectionAssert.AreEqual(expectedFiles, files, $"Expected: {string.Join (";", expectedFiles)}\n Found: {string.Join (";", files)}"); var assemblyPath = Path.Combine(outputPath, $"{proj.ProjectName}.dll"); FileAssert.Exists(assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath)) { var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest"; var type = assembly.MainModule.GetType(typeName); Assert.IsNotNull(type, $"{assemblyPath} should contain {typeName}"); } var rids = runtimeIdentifiers.Split(';'); if (isRelease) { // Check for stripped native libraries foreach (var rid in rids) { FileAssert.Exists(Path.Combine(intermediateOutputPath, "native", rid, "libmono-android.release.so")); FileAssert.Exists(Path.Combine(intermediateOutputPath, "native", rid, "libmonosgen-2.0.so")); } } bool expectEmbeddedAssembies = !(CommercialBuildAvailable && !isRelease); var apkPath = Path.Combine(outputPath, $"{proj.PackageName}.apk"); FileAssert.Exists(apkPath); using (var apk = ZipHelper.OpenZip(apkPath)) { apk.AssertContainsEntry(apkPath, $"assemblies/{proj.ProjectName}.dll", shouldContainEntry: expectEmbeddedAssembies); apk.AssertContainsEntry(apkPath, $"assemblies/{proj.ProjectName}.pdb", shouldContainEntry: !CommercialBuildAvailable && !isRelease); apk.AssertContainsEntry(apkPath, $"assemblies/System.Linq.dll", shouldContainEntry: expectEmbeddedAssembies); apk.AssertContainsEntry(apkPath, $"assemblies/es/{proj.ProjectName}.resources.dll", shouldContainEntry: expectEmbeddedAssembies); foreach (var abi in rids.Select(AndroidRidAbiHelper.RuntimeIdentifierToAbi)) { apk.AssertContainsEntry(apkPath, $"lib/{abi}/libmonodroid.so"); apk.AssertContainsEntry(apkPath, $"lib/{abi}/libmonosgen-2.0.so"); if (rids.Length > 1) { apk.AssertContainsEntry(apkPath, $"assemblies/{abi}/System.Private.CoreLib.dll", shouldContainEntry: expectEmbeddedAssembies); } else { apk.AssertContainsEntry(apkPath, "assemblies/System.Private.CoreLib.dll", shouldContainEntry: expectEmbeddedAssembies); } } } }
public static void AssertHasNoWarnings(this ProjectBuilder builder) { Assert.IsTrue(StringAssertEx.ContainsText(builder.LastBuildOutput, " 0 Warning(s)"), $"{builder.BuildLogFile} should have no MSBuild warnings."); }
public static void AssertHasNoWarnings(this DotNetCLI dotnet) { Assert.IsTrue(StringAssertEx.ContainsText(dotnet.LastBuildOutput, " 0 Warning(s)"), $"{dotnet.BuildLogFile} should have no MSBuild warnings."); }
public void CheckSignApk([Values(true, false)] bool useApkSigner, [Values(true, false)] bool perAbiApk) { string ext = Environment.OSVersion.Platform != PlatformID.Unix ? ".bat" : ""; var foundApkSigner = Directory.EnumerateDirectories(Path.Combine(AndroidSdkPath, "build-tools")).Any(dir => Directory.EnumerateFiles(dir, "apksigner" + ext).Any()); if (useApkSigner && !foundApkSigner) { Assert.Ignore("Skipping test. Required build-tools verison which contains apksigner is not installed."); } string keyfile = Path.Combine(Root, "temp", TestName, "release.keystore"); if (File.Exists(keyfile)) { File.Delete(keyfile); } var androidSdk = new AndroidSdkInfo((level, message) => { }, AndroidSdkPath, AndroidNdkPath); string keyToolPath = Path.Combine(androidSdk.JavaSdkPath, "bin"); var engine = new MockBuildEngine(Console.Out); string pass = "******"; var task = new AndroidCreateDebugKey { BuildEngine = engine, KeyStore = keyfile, StorePass = pass, KeyAlias = "releasestore", KeyPass = pass, KeyAlgorithm = "RSA", Validity = 30, StoreType = "pkcs12", Command = "-genkeypair", ToolPath = keyToolPath, }; Assert.IsTrue(task.Execute(), "Task should have succeeded."); var proj = new XamarinAndroidApplicationProject() { IsRelease = true, }; if (useApkSigner) { proj.SetProperty("AndroidUseApkSigner", "true"); } else { proj.RemoveProperty("AndroidUseApkSigner"); } proj.SetProperty(proj.ReleaseProperties, "AndroidKeyStore", "True"); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningKeyStore", keyfile); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningKeyAlias", "releasestore"); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningKeyPass", pass); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningStorePass", pass); proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, perAbiApk); proj.SetAndroidSupportedAbis("armeabi-v7a", "x86"); using (var b = CreateApkBuilder(Path.Combine("temp", TestContext.CurrentContext.Test.Name))) { var bin = Path.Combine(Root, b.ProjectDirectory, proj.OutputPath); Assert.IsTrue(b.Build(proj), "First build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)"), "First build should not contain warnings! Contains\n" + string.Join("\n", b.LastBuildOutput.Where(line => line.Contains("warning")))); //Make sure the APKs are signed foreach (var apk in Directory.GetFiles(bin, "*-Signed.apk")) { using (var zip = ZipHelper.OpenZip(apk)) { Assert.IsTrue(zip.Any(e => e.FullName == "META-INF/MANIFEST.MF"), $"APK file `{apk}` is not signed! It is missing `META-INF/MANIFEST.MF`."); } } var item = proj.AndroidResources.First(x => x.Include() == "Resources\\values\\Strings.xml"); item.TextContent = () => proj.StringsXml.Replace("${PROJECT_NAME}", "Foo"); item.Timestamp = null; Assert.IsTrue(b.Build(proj), "Second build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)"), "Second build should not contain warnings! Contains\n" + string.Join("\n", b.LastBuildOutput.Where(line => line.Contains("warning")))); //Make sure the APKs are signed foreach (var apk in Directory.GetFiles(bin, "*-Signed.apk")) { using (var zip = ZipHelper.OpenZip(apk)) { Assert.IsTrue(zip.Any(e => e.FullName == "META-INF/MANIFEST.MF"), $"APK file `{apk}` is not signed! It is missing `META-INF/MANIFEST.MF`."); } } } }
public void DotNetBuild(string runtimeIdentifiers, bool isRelease) { var proj = new XASdkProject { IsRelease = isRelease, Sources = { new BuildItem("EmbeddedResource", "Foo.resx") { TextContent = () => InlineData.ResxWithContents("<data name=\"CancelButton\"><value>Cancel</value></data>") }, new BuildItem("EmbeddedResource", "Foo.es.resx") { TextContent = () => InlineData.ResxWithContents("<data name=\"CancelButton\"><value>Cancelar</value></data>") }, } }; proj.OtherBuildItems.Add(new AndroidItem.InputJar("javaclasses.jar") { BinaryContent = () => ResourceData.JavaSourceJarTestJar, }); proj.OtherBuildItems.Add(new BuildItem("JavaSourceJar", "javaclasses-sources.jar") { BinaryContent = () => ResourceData.JavaSourceJarTestSourcesJar, }); if (!runtimeIdentifiers.Contains(";")) { proj.SetProperty(KnownProperties.RuntimeIdentifier, runtimeIdentifiers); } else { proj.SetProperty(KnownProperties.RuntimeIdentifiers, runtimeIdentifiers); } var dotnet = CreateDotNetBuilder(proj); Assert.IsTrue(dotnet.Build(), "`dotnet build` should succeed"); // TODO: run for release once illink warnings are gone // context: https://github.com/xamarin/xamarin-android/issues/4708 if (!isRelease) { Assert.IsTrue(StringAssertEx.ContainsText(dotnet.LastBuildOutput, " 0 Warning(s)"), "Should have no MSBuild warnings."); } var outputPath = Path.Combine(FullProjectDirectory, proj.OutputPath); if (!runtimeIdentifiers.Contains(";")) { outputPath = Path.Combine(outputPath, runtimeIdentifiers); } var files = Directory.EnumerateFileSystemEntries(outputPath) .Select(Path.GetFileName) .OrderBy(f => f) .ToArray(); var expectedFiles = new[] { "es", $"{proj.ProjectName}.dll", $"{proj.ProjectName}.pdb", $"{proj.PackageName}.apk", $"{proj.PackageName}-Signed.apk", $"{proj.ProjectName}.xml", }; CollectionAssert.AreEqual(expectedFiles, files, $"Expected: {string.Join (";", expectedFiles)}\n Found: {string.Join (";", files)}"); var assemblyPath = Path.Combine(outputPath, $"{proj.ProjectName}.dll"); FileAssert.Exists(assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath)) { var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest"; var type = assembly.MainModule.GetType(typeName); Assert.IsNotNull(type, $"{assemblyPath} should contain {typeName}"); } bool expectEmbeddedAssembies = !(CommercialBuildAvailable && !isRelease); var apkPath = Path.Combine(outputPath, "UnnamedProject.UnnamedProject.apk"); FileAssert.Exists(apkPath); using (var apk = ZipHelper.OpenZip(apkPath)) { apk.AssertContainsEntry(apkPath, $"assemblies/{proj.ProjectName}.dll", shouldContainEntry: expectEmbeddedAssembies); apk.AssertContainsEntry(apkPath, $"assemblies/{proj.ProjectName}.pdb", shouldContainEntry: !CommercialBuildAvailable && !isRelease); apk.AssertContainsEntry(apkPath, $"assemblies/System.Linq.dll", shouldContainEntry: expectEmbeddedAssembies); apk.AssertContainsEntry(apkPath, $"assemblies/es/{proj.ProjectName}.resources.dll", shouldContainEntry: expectEmbeddedAssembies); var rids = runtimeIdentifiers.Split(';'); foreach (var abi in rids.Select(AndroidRidAbiHelper.RuntimeIdentifierToAbi)) { apk.AssertContainsEntry(apkPath, $"lib/{abi}/libmonodroid.so"); apk.AssertContainsEntry(apkPath, $"lib/{abi}/libmonosgen-2.0.so"); if (rids.Length > 1) { apk.AssertContainsEntry(apkPath, $"assemblies/{abi}/System.Private.CoreLib.dll", shouldContainEntry: expectEmbeddedAssembies); } else { apk.AssertContainsEntry(apkPath, "assemblies/System.Private.CoreLib.dll", shouldContainEntry: expectEmbeddedAssembies); } } } }