public void BeforeDeploymentTests() { if (!HasDevices) { Assert.Ignore("Skipping Test. No devices available."); } string debuggable = RunAdbCommand("shell getprop ro.debuggable"); if (debuggable != "1") { Assert.Ignore("TimeZone tests need to use `su root` and this device does not support that feature. Try using an emulator."); } proj = new XamarinFormsAndroidApplicationProject(); proj.SetProperty(KnownProperties.AndroidSupportedAbis, "armeabi-v7a;x86"); var mainPage = proj.Sources.First(x => x.Include() == "MainPage.xaml.cs"); var source = mainPage.TextContent().Replace("InitializeComponent ();", @"InitializeComponent (); Console.WriteLine ($""TimeZoneInfo={TimeZoneInfo.Local.DisplayName}""); "); mainPage.TextContent = () => source; builder = CreateApkBuilder(Path.Combine("temp", "DeploymentTests")); string apiLevel; proj.TargetFrameworkVersion = builder.LatestTargetFrameworkVersion(out apiLevel); proj.PackageName = "Xamarin.TimeZoneTest"; proj.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""Xamarin.TimeZoneTest""> <uses-sdk android:minSdkVersion=""24"" android:targetSdkVersion=""{apiLevel}"" /> <application android:label=""${{PROJECT_NAME}}""> </application > </manifest> "; Assert.IsTrue(builder.Build(proj), "Build should have succeeded."); Assert.IsTrue(builder.Install(proj), "Install should have succeeded."); }
public void SetupDependenciesForDesigner() { var path = Path.Combine("temp", TestName); var lib = new XamarinAndroidLibraryProject { ProjectName = "Library1", OtherBuildItems = { new AndroidItem.AndroidAsset("Assets\\foo.txt") { TextContent = () => "Bar", }, }, }; var proj = new XamarinFormsAndroidApplicationProject { ProjectName = "App1", References = { new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj") }, }; using (var libb = CreateDllBuilder(Path.Combine(path, lib.ProjectName))) using (var appb = CreateApkBuilder(Path.Combine(path, proj.ProjectName))) { libb.Save(lib); Assert.IsTrue(appb.RunTarget(proj, "SetupDependenciesForDesigner", parameters: new [] { "DesignTimeBuild=True" }), "design-time build should have succeeded."); //Now a full build Assert.IsTrue(libb.Build(lib), "library build should have succeeded."); Assert.IsTrue(appb.Build(proj), "app build should have succeeded."); } }
public void ApplicationRunsWithoutDebugger([Values(false, true)] bool isRelease, [Values(false, true)] bool extractNativeLibs) { AssertHasDevices(); var proj = new XamarinFormsAndroidApplicationProject() { IsRelease = isRelease, }; if (isRelease || !CommercialBuildAvailable) { proj.SetAndroidSupportedAbis("armeabi-v7a", "x86"); } proj.SetDefaultTargetDevice(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { SetTargetFrameworkAndManifest(proj, b); proj.AndroidManifest = proj.AndroidManifest.Replace("<application ", $"<application android:extractNativeLibs=\"{extractNativeLibs.ToString ().ToLowerInvariant ()}\" "); Assert.True(b.Install(proj), "Project should have installed."); var manifest = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "AndroidManifest.xml"); AssertExtractNativeLibs(manifest, extractNativeLibs); ClearAdbLogcat(); if (CommercialBuildAvailable) { Assert.True(b.RunTarget(proj, "_Run"), "Project should have run."); } else { AdbStartActivity($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity"); } Assert.True(WaitForActivityToStart(proj.PackageName, "MainActivity", Path.Combine(Root, b.ProjectDirectory, "logcat.log"), 30), "Activity should have started."); Assert.True(b.Uninstall(proj), "Project should have uninstalled."); } }
public void ApplicationRunsWithoutDebugger([Values(false, true)] bool isRelease) { AssertHasDevices(); var proj = new XamarinFormsAndroidApplicationProject() { IsRelease = isRelease, }; if (isRelease || !CommercialBuildAvailable) { var abis = new string [] { "armeabi-v7a", "x86" }; proj.SetProperty(KnownProperties.AndroidSupportedAbis, string.Join(";", abis)); } proj.SetDefaultTargetDevice(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { SetTargetFrameworkAndManifest(proj, b); Assert.True(b.Install(proj), "Project should have installed."); ClearAdbLogcat(); if (CommercialBuildAvailable) { Assert.True(b.RunTarget(proj, "_Run"), "Project should have run."); } else { AdbStartActivity($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity"); } Assert.True(WaitForActivityToStart(proj.PackageName, "MainActivity", Path.Combine(Root, b.ProjectDirectory, "logcat.log"), 30), "Activity should have started."); Assert.True(b.Uninstall(proj), "Project should have uninstalled."); } }
public void CheckNothingIsDeletedByIncrementalClean([Values(true, false)] bool enableMultiDex, [Values(true, false)] bool useAapt2) { // do a release build // change one of the properties (say AotAssemblies) // do another build. it should NOT hose the resource directory. var path = Path.Combine("temp", TestName); var proj = new XamarinFormsAndroidApplicationProject() { ProjectName = "App1", IsRelease = true, }; if (enableMultiDex) { proj.SetProperty("AndroidEnableMultiDex", "True"); } if (useAapt2) { proj.SetProperty("AndroidUseAapt2", "True"); } using (var b = CreateApkBuilder(path)) { Assert.IsTrue(b.Build(proj), "First should have succeeded"); IEnumerable <string> files = Directory.EnumerateFiles(Path.Combine(Root, path, proj.IntermediateOutputPath), "*.*", SearchOption.AllDirectories); Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, parameters: null, saveProject: false), "Second should have succeeded"); foreach (var file in files) { FileAssert.Exists(file, $"{file} should not have been deleted!"); } } }
public void CheckNothingIsDeletedByIncrementalClean([Values(true, false)] bool enableMultiDex, [Values(true, false)] bool useAapt2) { var path = Path.Combine("temp", TestName); var proj = new XamarinFormsAndroidApplicationProject() { ProjectName = "App1", IsRelease = true, }; if (enableMultiDex) { proj.SetProperty("AndroidEnableMultiDex", "True"); } if (useAapt2) { proj.SetProperty("AndroidUseAapt2", "True"); } using (var b = CreateApkBuilder(path)) { //To be sure we are at a clean state var projectDir = Path.Combine(Root, b.ProjectDirectory); if (Directory.Exists(projectDir)) { Directory.Delete(projectDir, true); } Assert.IsTrue(b.Build(proj), "First should have succeeded"); var intermediate = Path.Combine(projectDir, proj.IntermediateOutputPath); var output = Path.Combine(projectDir, proj.OutputPath); var fileWrites = Path.Combine(intermediate, $"{proj.ProjectName}.csproj.FileListAbsolute.txt"); FileAssert.Exists(fileWrites); var expected = File.ReadAllText(fileWrites); var files = Directory.EnumerateFiles(intermediate, "*", SearchOption.AllDirectories).ToList(); files.AddRange(Directory.EnumerateFiles(output, "*", SearchOption.AllDirectories)); //Touch a few files, do an incremental build var filesToTouch = new [] { Path.Combine(intermediate, "build.props"), Path.Combine(intermediate, $"{proj.ProjectName}.pdb"), }; foreach (var file in filesToTouch) { FileAssert.Exists(file); File.SetLastWriteTimeUtc(file, DateTime.UtcNow); File.SetLastAccessTimeUtc(file, DateTime.UtcNow); } Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "Second should have succeeded"); //No changes Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "Third should have succeeded"); Assert.IsFalse(b.Output.IsTargetSkipped("IncrementalClean"), "`IncrementalClean` should have run!"); foreach (var file in files) { FileAssert.Exists(file, $"{file} should not have been deleted!"); } FileAssert.Exists(fileWrites); var actual = File.ReadAllText(fileWrites); Assert.AreEqual(expected, actual, $"`{fileWrites}` has changes!"); } }
public void DesignerBeforeNuGetRestore() { var path = Path.Combine("temp", TestName); var parameters = new [] { "DesignTimeBuild=True", "AndroidUseManagedDesignTimeResourceGenerator=False" }; var lib = new XamarinAndroidLibraryProject { ProjectName = "Library1", Sources = { new BuildItem.Source("Foo.cs") { TextContent = () => "public class Foo { }", } }, }; var proj = new XamarinFormsAndroidApplicationProject { ProjectName = "App1", References = { new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj") }, Sources = { new BuildItem.Source("Bar.cs") { TextContent = () => "public class Bar : Foo { }", } }, }; var dir = Path.Combine(Root, path); if (Directory.Exists(dir)) { Directory.Delete(dir, recursive: true); } using (var libb = CreateDllBuilder(Path.Combine(path, lib.ProjectName), false, false)) using (var appb = CreateApkBuilder(Path.Combine(path, proj.ProjectName), false, false)) { libb.AutomaticNuGetRestore = appb.AutomaticNuGetRestore = false; // Save the library project, but don't build it yet libb.Save(lib); appb.Target = "SetupDependenciesForDesigner"; Assert.IsTrue(appb.Build(proj, parameters: parameters), "first build should have succeeded"); var packageManagerPath = Path.Combine(Root, appb.ProjectDirectory, proj.IntermediateOutputPath, "android", "src", "mono", "MonoPackageManager.java"); var before = GetAssembliesFromPackageManager(packageManagerPath); Assert.AreEqual("", before, $"After first `{appb.Target}`, assemblies list would be empty."); libb.AutomaticNuGetRestore = appb.AutomaticNuGetRestore = true; Assert.IsTrue(appb.Build(proj, parameters: parameters), "second build should have succeeded"); var after = GetAssembliesFromPackageManager(packageManagerPath); Assert.AreNotEqual(before, after, $"After second `{appb.Target}`, assemblies list should *not* be empty."); foreach (var assembly in new [] { "Xamarin.Forms.Core.dll", "Xamarin.Forms.Platform.Android.dll" }) { StringAssert.Contains(assembly, after); } } }
public void ApplicationRunsWithoutDebugger([Values(false, true)] bool isRelease) { if (!HasDevices) { Assert.Ignore("Test needs a device attached."); return; } var proj = new XamarinFormsAndroidApplicationProject() { IsRelease = isRelease, }; if (isRelease || !CommercialBuildAvailable) { var abis = new string [] { "armeabi-v7a", "x86" }; proj.SetProperty(KnownProperties.AndroidSupportedAbis, string.Join(";", abis)); } proj.SetDefaultTargetDevice(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { string apiLevel; proj.TargetFrameworkVersion = b.LatestTargetFrameworkVersion(out apiLevel); proj.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""UnnamedProject.UnnamedProject""> <uses-sdk android:minSdkVersion=""24"" android:targetSdkVersion=""{apiLevel}"" /> <application android:label=""${{PROJECT_NAME}}""> </application > </manifest>"; b.Save(proj, saveProject: true); proj.NuGetRestore(Path.Combine(Root, b.ProjectDirectory), b.PackagesDirectory); Assert.True(b.Build(proj), "Project should have built."); Assert.True(b.Install(proj), "Project should have installed."); ClearAdbLogcat(); if (CommercialBuildAvailable) { Assert.True(b.RunTarget(proj, "_Run"), "Project should have run."); } else { AdbStartActivity($"{proj.PackageName}/md52d9cf6333b8e95e8683a477bc589eda5.MainActivity"); } string logcatPath = Path.Combine(XABuildPaths.TestOutputDirectory, b.ProjectDirectory, "logcat.log"); bool didActivityStart = WaitForActivityToStart(proj.PackageName, "MainActivity", output: out string logcatOutput, timeout: 30); File.WriteAllText(logcatPath, logcatOutput); Assert.True(didActivityStart, "Activity should have started."); Assert.True(b.Uninstall(proj), "Project should have uninstalled."); } }
public void BeforeDeploymentTests() { AssertHasDevices(); string debuggable = RunAdbCommand("shell getprop ro.debuggable"); if (debuggable != "1") { Assert.Ignore("TimeZone tests need to use `su root` and this device does not support that feature. Try using an emulator."); } // Disable auto timezone RunAdbCommand("shell settings put global auto_time_zone 0"); proj = new XamarinFormsAndroidApplicationProject(); proj.SetAndroidSupportedAbis("armeabi-v7a", "x86"); var mainPage = proj.Sources.First(x => x.Include() == "MainPage.xaml.cs"); var source = mainPage.TextContent().Replace("InitializeComponent ();", @"InitializeComponent (); Console.WriteLine ($""TimeZoneInfoNative={Java.Util.TimeZone.Default.ID}""); Console.WriteLine ($""TimeZoneInfo={TimeZoneInfo.Local.DisplayName}""); "); source = source.Replace("Console.WriteLine (\"Button was Clicked!\");", @"Console.WriteLine (""Button was Clicked!""); Console.WriteLine ($""TimeZoneInfoClick={TimeZoneInfo.Local.DisplayName}""); "); mainPage.TextContent = () => source; builder = CreateApkBuilder(Path.Combine("temp", "DeploymentTests")); string apiLevel; proj.TargetFrameworkVersion = builder.LatestTargetFrameworkVersion(out apiLevel); // TODO: We aren't sure how to support preview bindings in .NET6 yet. if (Builder.UseDotNet && apiLevel == "31") { apiLevel = "30"; proj.TargetFrameworkVersion = "v11.0"; } proj.PackageName = "Xamarin.TimeZoneTest"; proj.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""Xamarin.TimeZoneTest""> <uses-sdk android:minSdkVersion=""24"" android:targetSdkVersion=""{apiLevel}"" /> <application android:label=""${{PROJECT_NAME}}""> </application > </manifest> "; Assert.IsTrue(builder.Build(proj), "Build should have succeeded."); Assert.IsTrue(builder.Install(proj), "Install should have succeeded."); }
public void AppProjectTargetsDoNotBreak() { var targets = new [] { "_CopyIntermediateAssemblies", "_GeneratePackageManagerJava", "_ResolveLibraryProjectImports", "_BuildAdditionalResourcesCache", "_CleanIntermediateIfNuGetsChange", }; var proj = new XamarinFormsAndroidApplicationProject(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "first build should succeed"); foreach (var target in targets) { Assert.IsFalse(b.Output.IsTargetSkipped(target), $"`{target}` should *not* be skipped!"); } var intermediate = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath); var filesToTouch = new [] { Path.Combine(intermediate, "build.props"), Path.Combine(intermediate, proj.ProjectName + ".dll"), Path.Combine(intermediate, "android", "assets", proj.ProjectName + ".dll"), Path.Combine(Root, b.ProjectDirectory, "packages.config"), }; foreach (var file in filesToTouch) { FileAssert.Exists(file); File.SetLastWriteTimeUtc(file, DateTime.UtcNow); File.SetLastAccessTimeUtc(file, DateTime.UtcNow); } //NOTE: second build, targets will run because inputs changed Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "second build should succeed"); foreach (var target in targets) { Assert.IsFalse(b.Output.IsTargetSkipped(target), $"`{target}` should *not* be skipped on second build!"); } //NOTE: third build, targets should certainly *not* run! there are no changes Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "third build should succeed"); foreach (var target in targets) { Assert.IsTrue(b.Output.IsTargetSkipped(target), $"`{target}` should be skipped on third build!"); } } }
public void LinkAssembliesNoShrink() { var proj = new XamarinFormsAndroidApplicationProject(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "build should have succeeded."); // Touch an assembly to a timestamp older than build.props var formsViewGroup = b.Output.GetIntermediaryPath(Path.Combine("android", "assets", "FormsViewGroup.dll")); File.SetLastWriteTimeUtc(formsViewGroup, new DateTime(1970, 1, 1)); Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true), "build should have succeeded."); Assert.IsFalse(b.Output.IsTargetSkipped("_LinkAssembliesNoShrink"), "_LinkAssembliesNoShrink should *not* be skipped."); // No changes Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true), "build should have succeeded."); Assert.IsTrue(b.Output.IsTargetSkipped("_LinkAssembliesNoShrink"), "_LinkAssembliesNoShrink should be skipped."); } }
public void InstantRunSimpleBuild([Values("dx", "d8")] string dexTool) { if (!CommercialBuildAvailable) { Assert.Ignore("Not required on Open Source Builds"); } if (!HasDevices) { Assert.Ignore("Test needs a device attached."); return; } var proj = new XamarinFormsAndroidApplicationProject { AndroidFastDeploymentType = "Assemblies:Dexes", UseLatestPlatformSdk = true, DexTool = dexTool, }; var b = CreateApkBuilder(Path.Combine("temp", TestName)); Assert.IsTrue(b.Clean(proj), "Clean should have succeeded."); Assert.IsTrue(b.Build(proj), "Build should have succeeded."); var manifest = b.Output.GetIntermediaryAsText(BuildOutputFiles.AndroidManifest); Assert.IsTrue(File.Exists(b.Output.GetIntermediaryPath("android/bin/dex/mono.android.dex")), "there should be mono.android.dex in the intermediaries."); using (var apk = ((AndroidApplicationBuildOutput)b.Output).OpenApk()) { var dexFile = Path.GetTempFileName(); File.WriteAllBytes(dexFile, apk.GetRaw(ApkContents.ClassesDex)); try { string className = "Lcom/xamarin/forms/platform/android/FormsViewGroup;"; Assert.IsFalse(DexUtils.ContainsClass(className, dexFile, AndroidSdkPath), $"`{dexFile}` should *not* include `{className}`!"); className = "Lmono/MonoRuntimeProvider;"; Assert.IsFalse(DexUtils.ContainsClass(className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); className = "Lmono/MonoPackageManager;"; Assert.IsTrue(DexUtils.ContainsClass(className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); } finally { File.Delete(dexFile); } } b.Dispose(); }
public void ResolveLibraryProjectImports() { var proj = new XamarinFormsAndroidApplicationProject(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "first build should have succeeded."); var intermediate = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath); var cacheFile = Path.Combine(intermediate, "libraryprojectimports.cache"); FileAssert.Exists(cacheFile); var expected = ReadCache(cacheFile); Assert.AreNotEqual(0, expected.Jars.Length, $"{nameof (expected.Jars)} should not be empty"); Assert.AreNotEqual(0, expected.ResolvedResourceDirectories.Length, $"{nameof (expected.ResolvedResourceDirectories)} should not be empty"); // Delete the stamp file; this triggers <ResolveLibraryProjectImports/> to re-run. // However, the task will skip everything, since the hashes of each assembly will be the same. var stamp = Path.Combine(intermediate, "stamp", "_ResolveLibraryProjectImports.stamp"); FileAssert.Exists(stamp); File.Delete(stamp); Assert.IsTrue(b.Build(proj), "second build should have succeeded."); var actual = ReadCache(cacheFile); CollectionAssert.AreEqual(actual.Jars.Select(j => j.ItemSpec), expected.Jars.Select(j => j.ItemSpec)); CollectionAssert.AreEqual(actual.ResolvedResourceDirectories.Select(j => j.ItemSpec), expected.ResolvedResourceDirectories.Select(j => j.ItemSpec)); // Add a new AAR file to the project var aar = new AndroidItem.AndroidAarLibrary("Jars\\android-crop-1.0.1.aar") { WebContent = "https://jcenter.bintray.com/com/soundcloud/android/android-crop/1.0.1/android-crop-1.0.1.aar" }; proj.OtherBuildItems.Add(aar); Assert.IsTrue(b.Build(proj), "third build should have succeeded."); actual = ReadCache(cacheFile); Assert.AreEqual(expected.Jars.Length + 1, actual.Jars.Length, $"{nameof (expected.Jars)} should have one more item"); Assert.AreEqual(expected.ResolvedResourceDirectories.Length + 1, actual.ResolvedResourceDirectories.Length, $"{nameof (expected.ResolvedResourceDirectories)} should have one more item"); } }
public void IncrementalDesignTimeBuild() { var proj = new XamarinFormsAndroidApplicationProject(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { b.Target = "SetupDependenciesForDesigner"; Assert.IsTrue(b.Build(proj, parameters: DesignerParameters), $"{b.Target} should have succeeded."); // Change a layout, DTB proj.LayoutMain = proj.LayoutMain.Replace("@string/hello", "hello"); proj.Touch("Resources\\layout\\Main.axml"); Assert.IsTrue(b.DesignTimeBuild(proj, target: "UpdateGeneratedFiles"), "DTB should have succeeded."); var resourcepathscache = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "designtime", "libraryprojectimports.cache"); FileAssert.Exists(resourcepathscache); var doc = XDocument.Load(resourcepathscache); Assert.AreEqual(40, doc.Root.Element("Jars").Elements("Jar").Count(), "libraryprojectimports.cache did not contain expected jar files"); } }
public void CopyIntermediateAssemblies() { var target = "_CopyIntermediateAssemblies"; var proj = new XamarinFormsAndroidApplicationProject(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "first build should succeed"); Assert.IsFalse(b.Output.IsTargetSkipped(target), $"`{target}` should *not* be skipped!"); var assembly = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, proj.ProjectName + ".dll"); FileAssert.Exists(assembly); File.SetLastWriteTimeUtc(assembly, DateTime.UtcNow); File.SetLastAccessTimeUtc(assembly, DateTime.UtcNow); //NOTE: second build, target will run because inputs changed Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "second build should succeed"); Assert.IsFalse(b.Output.IsTargetSkipped(target), $"`{target}` should *not* be skipped on second build!"); //NOTE: third build, it should certainly *not* run! there are no changes Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "third build should succeed"); Assert.IsTrue(b.Output.IsTargetSkipped(target), $"`{target}` should be skipped on third build!"); } }
public void BeforeDeploymentTests() { proj = new XamarinFormsAndroidApplicationProject(); proj.SetProperty(KnownProperties.AndroidSupportedAbis, "armeabi-v7a;x86"); var mainPage = proj.Sources.First(x => x.Include() == "MainPage.xaml.cs"); var source = mainPage.TextContent().Replace("InitializeComponent ();", @"InitializeComponent (); Console.WriteLine ($""TimeZoneInfo={TimeZoneInfo.Local.DisplayName}""); "); mainPage.TextContent = () => source; builder = CreateApkBuilder(Path.Combine("temp", "DeploymentTests")); string apiLevel; proj.TargetFrameworkVersion = builder.LatestTargetFrameworkVersion(out apiLevel); proj.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""UnnamedProject.UnnamedProject""> <uses-sdk android:minSdkVersion=""24"" android:targetSdkVersion=""{apiLevel}"" /> <application android:label=""${{PROJECT_NAME}}""> </application > </manifest> "; Assert.IsTrue(builder.Build(proj), "Build should have succeeded."); Assert.IsTrue(builder.Install(proj), "Install should have succeeded."); }
public void IncrementalFastDeployment() { AssertCommercialBuild(); AssertHasDevices(); var class1src = new BuildItem.Source("Class1.cs") { TextContent = () => "namespace Library1 { public class Class1 { public static int foo = 0; } }" }; var lib1 = new XamarinAndroidLibraryProject() { ProjectName = "Library1", Sources = { class1src, } }; var class2src = new BuildItem.Source("Class2.cs") { TextContent = () => "namespace Library2 { public class Class2 { public static int foo = 0; } }" }; var lib2 = new DotNetStandard { ProjectName = "Library2", Sdk = "Microsoft.NET.Sdk", TargetFramework = "netstandard2.0", Sources = { class2src, } }; var app = new XamarinFormsAndroidApplicationProject() { EmbedAssembliesIntoApk = false, References = { new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj"), new BuildItem("ProjectReference", "..\\Library2\\Library2.csproj"), }, }; // Set up library projects var rootPath = Path.Combine(Root, "temp", TestName); using (var lb1 = CreateDllBuilder(Path.Combine(rootPath, lib1.ProjectName))) Assert.IsTrue(lb1.Build(lib1), "First library build should have succeeded."); using (var lb2 = CreateDllBuilder(Path.Combine(rootPath, lib2.ProjectName))) Assert.IsTrue(lb2.Build(lib2), "Second library build should have succeeded."); long lib1FirstBuildSize = new FileInfo(Path.Combine(rootPath, lib1.ProjectName, lib1.OutputPath, "Library1.dll")).Length; using (var builder = CreateApkBuilder(Path.Combine(rootPath, app.ProjectName))) { builder.ThrowOnBuildFailure = false; builder.BuildLogFile = "install.log"; Assert.IsTrue(builder.Install(app), "First install should have succeeded."); var logLines = builder.LastBuildOutput; Assert.IsTrue(logLines.Any(l => l.Contains("NotifySync CopyFile") && l.Contains("UnnamedProject.dll")), "UnnamedProject.dll should have been uploaded"); Assert.IsTrue(logLines.Any(l => l.Contains("NotifySync CopyFile") && l.Contains("Library1.dll")), "Library1.dll should have been uploaded"); Assert.IsTrue(logLines.Any(l => l.Contains("NotifySync CopyFile") && l.Contains("Library2.dll")), "Library2.dll should have been uploaded"); var firstInstallTime = builder.LastBuildTime; builder.BuildLogFile = "install2.log"; Assert.IsTrue(builder.Install(app, doNotCleanupOnUpdate: true, saveProject: false), "Second install should have succeeded."); var secondInstallTime = builder.LastBuildTime; var filesToTouch = new [] { Path.Combine(rootPath, lib2.ProjectName, "Class2.cs"), Path.Combine(rootPath, app.ProjectName, "MainPage.xaml"), }; foreach (var file in filesToTouch) { FileAssert.Exists(file); File.SetLastWriteTimeUtc(file, DateTime.UtcNow); } class1src.TextContent = () => "namespace Library1 { public class Class1 { public static int foo = 100; } }"; class1src.Timestamp = DateTime.UtcNow.AddSeconds(1); using (var lb1 = CreateDllBuilder(Path.Combine(rootPath, lib1.ProjectName))) Assert.IsTrue(lb1.Build(lib1), "Second library build should have succeeded."); long lib1SecondBuildSize = new FileInfo(Path.Combine(rootPath, lib1.ProjectName, lib1.OutputPath, "Library1.dll")).Length; Assert.AreEqual(lib1FirstBuildSize, lib1SecondBuildSize, "Library2.dll was not the same size."); builder.BuildLogFile = "install3.log"; Assert.IsTrue(builder.Install(app, doNotCleanupOnUpdate: true, saveProject: false), "Third install should have succeeded."); logLines = builder.LastBuildOutput; Assert.IsTrue(logLines.Any(l => l.Contains("NotifySync CopyFile") && l.Contains("UnnamedProject.dll")), "UnnamedProject.dll should have been uploaded"); Assert.IsTrue(logLines.Any(l => l.Contains("NotifySync CopyFile") && l.Contains("Library1.dll")), "Library1.dll should have been uploaded"); Assert.IsTrue(logLines.Any(l => l.Contains("NotifySync SkipCopyFile") && l.Contains("Library2.dll")), "Library2.dll should not have been uploaded"); var thirdInstallTime = builder.LastBuildTime; builder.BuildLogFile = "install4.log"; Assert.IsTrue(builder.Install(app, doNotCleanupOnUpdate: true, saveProject: false), "Fourth install should have succeeded."); var fourthInstalTime = builder.LastBuildTime; Assert.IsTrue(thirdInstallTime < firstInstallTime, $"Third incremental install: '{thirdInstallTime}' should be faster than clean install: '{firstInstallTime}'."); Assert.IsTrue(secondInstallTime < firstInstallTime && secondInstallTime < thirdInstallTime, $"Second unchanged install: '{secondInstallTime}' should be faster than clean install: '{firstInstallTime}' and incremental install: '{thirdInstallTime}'."); Assert.IsTrue(fourthInstalTime < firstInstallTime && fourthInstalTime < thirdInstallTime, $"Fourth unchanged install: '{fourthInstalTime}' should be faster than clean install: '{firstInstallTime}' and incremental install: '{thirdInstallTime}'."); } }
public void IncrementalFastDeployment() { AssertCommercialBuild(); AssertHasDevices(); var lib1 = new XamarinAndroidLibraryProject() { ProjectName = "Library1", Sources = { new BuildItem.Source("Class1.cs") { TextContent = () => "namespace Library1 { public class Class1 { } }" }, } }; var lib2 = new DotNetStandard { ProjectName = "Library2", Sdk = "Microsoft.NET.Sdk", TargetFramework = "netstandard2.0", Sources = { new BuildItem.Source("Class2.cs") { TextContent = () => "namespace Library2 { public class Class2 { } }" }, } }; var app = new XamarinFormsAndroidApplicationProject() { AndroidUseSharedRuntime = true, EmbedAssembliesIntoApk = false, References = { new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj"), new BuildItem("ProjectReference", "..\\Library2\\Library2.csproj"), }, }; // Set up library projects var rootPath = Path.Combine(Root, "temp", TestName); using (var lb1 = CreateDllBuilder(Path.Combine(rootPath, lib1.ProjectName))) Assert.IsTrue(lb1.Build(lib1), "First library build should have succeeded."); using (var lb2 = CreateDllBuilder(Path.Combine(rootPath, lib2.ProjectName))) Assert.IsTrue(lb2.Build(lib2), "Second library build should have succeeded."); using (var builder = CreateApkBuilder(Path.Combine(rootPath, app.ProjectName))) { builder.ThrowOnBuildFailure = false; Assert.IsTrue(builder.Install(app), "First install should have succeeded."); var firstInstallTime = builder.LastBuildTime; Assert.IsTrue(builder.Install(app, doNotCleanupOnUpdate: true, saveProject: false), "Second install should have succeeded."); var secondInstallTime = builder.LastBuildTime; var filesToTouch = new [] { Path.Combine(rootPath, lib1.ProjectName, "Class1.cs"), Path.Combine(rootPath, lib2.ProjectName, "Class2.cs"), Path.Combine(rootPath, app.ProjectName, "MainPage.xaml"), }; foreach (var file in filesToTouch) { FileAssert.Exists(file); File.SetLastWriteTimeUtc(file, DateTime.UtcNow); } Assert.IsTrue(builder.Install(app, doNotCleanupOnUpdate: true, saveProject: false), "Third install should have succeeded."); var thirdInstallTime = builder.LastBuildTime; Assert.IsTrue(builder.Install(app, doNotCleanupOnUpdate: true, saveProject: false), "Fourth install should have succeeded."); var fourthInstalTime = builder.LastBuildTime; Assert.IsTrue(thirdInstallTime < firstInstallTime, $"Third incremental install: '{thirdInstallTime}' should be faster than clean install: '{firstInstallTime}'."); Assert.IsTrue(secondInstallTime < firstInstallTime && secondInstallTime < thirdInstallTime, $"Second unchanged install: '{secondInstallTime}' should be faster than clean install: '{firstInstallTime}' and incremental install: '{thirdInstallTime}'."); Assert.IsTrue(fourthInstalTime < firstInstallTime && fourthInstalTime < thirdInstallTime, $"Fourth unchanged install: '{fourthInstalTime}' should be faster than clean install: '{firstInstallTime}' and incremental install: '{thirdInstallTime}'."); } }
public void Build_XAML_Change(bool produceReferenceAssembly, bool install) { if (install) { AssertCommercialBuild(); // This test will fail without Fast Deployment AssertHasDevices(); } var path = Path.Combine("temp", TestName); var xaml = @"<?xml version=""1.0"" encoding=""utf-8"" ?> <ContentPage xmlns=""http://xamarin.com/schemas/2014/forms"" xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml"" x:Class=""MyLibrary.MyPage""> </ContentPage>"; var caller = nameof(Build_XAML_Change); if (install) { caller = caller.Replace("Build", "Install"); } else if (produceReferenceAssembly) { caller += "_RefAssembly"; } var app = new XamarinFormsAndroidApplicationProject { ProjectName = "MyApp", Sources = { new BuildItem.Source("Foo.cs") { TextContent = () => "public class Foo : Bar { }" }, } }; //NOTE: this will skip a 382ms <VerifyVersionsTask/> from the support library app.SetProperty("XamarinAndroidSupportSkipVerifyVersions", "True"); int count = 0; var lib = new DotNetStandard { ProjectName = "MyLibrary", Sdk = "Microsoft.NET.Sdk", TargetFramework = "netstandard2.0", Sources = { new BuildItem.Source("Bar.cs") { TextContent = () => "public class Bar { public Bar () { System.Console.WriteLine (" + count++ + "); } }" }, new BuildItem("EmbeddedResource", "MyPage.xaml") { TextContent = () => xaml, } }, PackageReferences = { KnownPackages.XamarinForms_4_0_0_425677 } }; lib.SetProperty("ProduceReferenceAssembly", produceReferenceAssembly.ToString()); app.References.Add(new BuildItem.ProjectReference($"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj", lib.ProjectName, lib.ProjectGuid)); using (var libBuilder = CreateDllBuilder(Path.Combine(path, lib.ProjectName))) using (var appBuilder = CreateBuilderWithoutLogFile(Path.Combine(path, app.ProjectName))) { libBuilder.Build(lib); appBuilder.Target = "Build"; if (install) { appBuilder.Install(app); } else { appBuilder.Build(app); } libBuilder.AutomaticNuGetRestore = appBuilder.AutomaticNuGetRestore = false; // Profile XAML change xaml += $"{Environment.NewLine}<!--comment-->"; lib.Touch("MyPage.xaml"); libBuilder.Build(lib, doNotCleanupOnUpdate: true); if (install) { Profile(appBuilder, b => b.Install(app, doNotCleanupOnUpdate: true), caller); } else { Profile(appBuilder, b => b.Build(app, doNotCleanupOnUpdate: true), caller); } } }
static void Main() { var temp = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location)); using (builder = new ProjectBuilder(Path.Combine("temp", "Fuzzer")) { AutomaticNuGetRestore = false, CleanupAfterSuccessfulBuild = false, CleanupOnDispose = true, Root = Xamarin.Android.Build.Paths.TestOutputDirectory, }) { directory = Path.GetFullPath(Path.Combine(builder.Root, builder.ProjectDirectory)); if (Directory.Exists(directory)) { Directory.Delete(directory, recursive: true); } application = new XamarinFormsAndroidApplicationProject(); application.AndroidManifest = application.AndroidManifest.Replace("<uses-sdk />", "<uses-sdk android:targetSdkVersion=\"28\" />"); application.MainActivity = application.DefaultMainActivity.Replace("//${AFTER_ONCREATE}", "Android.Util.Log.Debug (\"FUZZER\", \"App started!\");"); var abis = new string [] { "armeabi-v7a", "arm64-v8a", "x86" }; application.SetProperty(KnownProperties.AndroidSupportedAbis, string.Join(";", abis)); if (!NuGetRestore()) { Console.WriteLine("Initial NuGet restore failed!"); return; } Func <bool> [] operations = { AddClass, AddResource, Build, ChangePackageName, Clean, DesignerBuild, DesignTimeBuild, Install, NuGetRestore, RemoveClass, RemoveResource, RenameClass, RenameResource, Run, TouchRandomFile, Uninstall, }; while (true) { var operation = operations [random.Next(operations.Length)]; if (!operation()) { break; } } } Console.WriteLine("Press enter to exit..."); Console.ReadLine(); }
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 ApplicationRunsWithDebuggerAndBreaks(bool useSharedRuntime, bool embedAssemblies, string fastDevType, bool allowDeltaInstall) { AssertCommercialBuild(); AssertHasDevices(); var proj = new XamarinFormsAndroidApplicationProject() { IsRelease = false, AndroidUseSharedRuntime = useSharedRuntime, EmbedAssembliesIntoApk = embedAssemblies, AndroidFastDeploymentType = fastDevType }; var abis = new string [] { "armeabi-v7a", "x86" }; proj.SetProperty(KnownProperties.AndroidSupportedAbis, string.Join(";", abis)); if (allowDeltaInstall) { proj.SetProperty(KnownProperties._AndroidAllowDeltaInstall, "true"); } proj.SetDefaultTargetDevice(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { SetTargetFrameworkAndManifest(proj, b); Assert.True(b.Install(proj), "Project should have installed."); int breakcountHitCount = 0; ManualResetEvent resetEvent = new ManualResetEvent(false); var sw = new Stopwatch(); // setup the debugger var session = new SoftDebuggerSession(); session.Breakpoints = new BreakpointStore { { Path.Combine(Root, b.ProjectDirectory, "MainActivity.cs"), 20 }, { Path.Combine(Root, b.ProjectDirectory, "MainPage.xaml.cs"), 14 }, { Path.Combine(Root, b.ProjectDirectory, "MainPage.xaml.cs"), 19 }, { Path.Combine(Root, b.ProjectDirectory, "App.xaml.cs"), 12 }, }; session.TargetHitBreakpoint += (sender, e) => { TestContext.WriteLine($"BREAK {e.Type}, {e.Backtrace.GetFrame (0)}"); breakcountHitCount++; session.Continue(); }; var rnd = new Random(); int port = rnd.Next(10000, 20000); TestContext.Out.WriteLine($"{port}"); var args = new SoftDebuggerConnectArgs("", IPAddress.Loopback, port) { MaxConnectionAttempts = 10, }; var startInfo = new SoftDebuggerStartInfo(args) { WorkingDirectory = Path.Combine(b.ProjectDirectory, proj.IntermediateOutputPath, "android", "assets"), }; var options = new DebuggerSessionOptions() { EvaluationOptions = EvaluationOptions.DefaultOptions, }; options.EvaluationOptions.UseExternalTypeResolver = true; ClearAdbLogcat(); Assert.True(b.RunTarget(proj, "_Run", parameters: new string [] { $"AndroidSdbTargetPort={port}", $"AndroidSdbHostPort={port}", "AndroidAttachDebugger=True", }), "Project should have run."); Assert.IsTrue(WaitForDebuggerToStart(Path.Combine(Root, b.ProjectDirectory, "logcat.log")), "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); }; session.OutputWriter += (isStderr, text) => { Console.WriteLine(text); }; session.DebugWriter += (level, category, message) => { Console.WriteLine(message); }; session.Run(startInfo, options); WaitFor(TimeSpan.FromSeconds(30), () => session.IsConnected); Assert.True(session.IsConnected, "Debugger should have connected but it did not."); // we need to wait here for a while to allow the breakpoints to hit // but we need to timeout TimeSpan timeout = TimeSpan.FromSeconds(60); int expected = 3; while (session.IsConnected && breakcountHitCount < 3 && timeout >= TimeSpan.Zero) { Thread.Sleep(10); timeout = timeout.Subtract(TimeSpan.FromMilliseconds(10)); } WaitFor(2000); Assert.AreEqual(expected, breakcountHitCount, $"Should have hit {expected} breakpoints. Only hit {breakcountHitCount}"); breakcountHitCount = 0; ClearAdbLogcat(); ClickButton(proj.PackageName, "myXFButton", "CLICK ME"); while (session.IsConnected && breakcountHitCount < 1 && timeout >= TimeSpan.Zero) { Thread.Sleep(10); timeout = timeout.Subtract(TimeSpan.FromMilliseconds(10)); } expected = 1; Assert.AreEqual(expected, breakcountHitCount, $"Should have hit {expected} breakpoints. Only hit {breakcountHitCount}"); Assert.True(b.Uninstall(proj), "Project should have uninstalled."); session.Exit(); } }
public void AppProjectTargetsDoNotBreak() { var targets = new List <string> { "_CopyIntermediateAssemblies", "_GeneratePackageManagerJava", "_ResolveLibraryProjectImports", "_BuildAdditionalResourcesCache", "_CleanIntermediateIfNuGetsChange", "_CopyConfigFiles", "_CopyPdbFiles", }; var proj = new XamarinFormsAndroidApplicationProject { OtherBuildItems = { new BuildItem.NoActionResource("UnnamedProject.dll.config") { TextContent = () => "<?xml version='1.0' ?><configuration/>", Metadata = { { "CopyToOutputDirectory", "PreserveNewest" }, } } } }; if (IsWindows) { //NOTE: pdb2mdb will run on Windows on the current project's symbols if DebugType=Full proj.SetProperty(proj.DebugProperties, "DebugType", "Full"); targets.Add("_CopyMdbFiles"); targets.Add("_ConvertPdbFiles"); } using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "first build should succeed"); foreach (var target in targets) { Assert.IsFalse(b.Output.IsTargetSkipped(target), $"`{target}` should *not* be skipped!"); } var output = Path.Combine(Root, b.ProjectDirectory, proj.OutputPath); var intermediate = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath); var filesToTouch = new [] { Path.Combine(intermediate, "..", "project.assets.json"), Path.Combine(intermediate, "build.props"), Path.Combine(intermediate, $"{proj.ProjectName}.dll"), Path.Combine(intermediate, $"{proj.ProjectName}.pdb"), Path.Combine(intermediate, "android", "assets", $"{proj.ProjectName}.dll"), Path.Combine(output, $"{proj.ProjectName}.dll.config"), }; foreach (var file in filesToTouch) { FileAssert.Exists(file); File.SetLastWriteTimeUtc(file, DateTime.UtcNow); File.SetLastAccessTimeUtc(file, DateTime.UtcNow); } //NOTE: second build, targets will run because inputs changed Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "second build should succeed"); foreach (var target in targets) { Assert.IsFalse(b.Output.IsTargetSkipped(target), $"`{target}` should *not* be skipped on second build!"); } //NOTE: third build, targets should certainly *not* run! there are no changes Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "third build should succeed"); foreach (var target in targets) { Assert.IsTrue(b.Output.IsTargetSkipped(target), $"`{target}` should be skipped on third build!"); } } }
public void ApplicationRunsWithDebuggerAndBreaks(bool embedAssemblies, string fastDevType, bool allowDeltaInstall, string username) { AssertCommercialBuild(); AssertHasDevices(); var path = Path.Combine("temp", TestName); int userId = GetUserId(username); List <string> parameters = new List <string> (); if (userId >= 0) { parameters.Add($"AndroidDeviceUserId={userId}"); } if (SwitchUser(username)) { WaitFor(5); ClickButton("", "android:id/button1", "Yes continue"); } var lib = new XamarinAndroidLibraryProject { ProjectName = "Library1", Sources = { new BuildItem.Source("Foo.cs") { TextContent = () => @"public class Foo { public Foo () { } }" }, }, }; var app = new XamarinFormsAndroidApplicationProject { ProjectName = "App", IsRelease = false, EmbedAssembliesIntoApk = embedAssemblies, AndroidFastDeploymentType = fastDevType }; app.MainPage = app.MainPage.Replace("InitializeComponent ();", "InitializeComponent (); new Foo ();"); app.AddReference(lib); app.SetAndroidSupportedAbis("armeabi-v7a", "x86"); app.SetProperty(KnownProperties._AndroidAllowDeltaInstall, allowDeltaInstall.ToString()); app.SetDefaultTargetDevice(); using (var libBuilder = CreateDllBuilder(Path.Combine(path, lib.ProjectName))) using (var appBuilder = CreateApkBuilder(Path.Combine(path, app.ProjectName))) { Assert.True(libBuilder.Build(lib), "Library should have built."); SetTargetFrameworkAndManifest(app, appBuilder); Assert.True(appBuilder.Install(app, parameters: parameters.ToArray()), "App should have installed."); if (!embedAssemblies) { // Check that we deployed .pdb files StringAssertEx.ContainsRegex($@"NotifySync CopyFile.+{app.ProjectName}\.pdb", appBuilder.LastBuildOutput, $"{app.ProjectName}.pdb should be deployed!"); StringAssertEx.ContainsRegex($@"NotifySync CopyFile.+{lib.ProjectName}\.pdb", appBuilder.LastBuildOutput, $"{lib.ProjectName}.pdb should be deployed!"); } int breakcountHitCount = 0; ManualResetEvent resetEvent = new ManualResetEvent(false); var sw = new Stopwatch(); // setup the debugger var session = new SoftDebuggerSession(); session.Breakpoints = new BreakpointStore { { Path.Combine(Root, appBuilder.ProjectDirectory, "MainActivity.cs"), 20 }, { Path.Combine(Root, appBuilder.ProjectDirectory, "MainPage.xaml.cs"), 14 }, { Path.Combine(Root, appBuilder.ProjectDirectory, "MainPage.xaml.cs"), 19 }, { Path.Combine(Root, appBuilder.ProjectDirectory, "App.xaml.cs"), 12 }, { Path.Combine(Root, libBuilder.ProjectDirectory, "Foo.cs"), 4 }, }; session.TargetHitBreakpoint += (sender, e) => { TestContext.WriteLine($"BREAK {e.Type}, {e.Backtrace.GetFrame (0)}"); breakcountHitCount++; session.Continue(); }; var rnd = new Random(); int port = rnd.Next(10000, 20000); TestContext.Out.WriteLine($"{port}"); var args = new SoftDebuggerConnectArgs("", IPAddress.Loopback, port) { MaxConnectionAttempts = 10, }; var startInfo = new SoftDebuggerStartInfo(args) { WorkingDirectory = Path.Combine(appBuilder.ProjectDirectory, app.IntermediateOutputPath, "android", "assets"), }; var options = new DebuggerSessionOptions() { EvaluationOptions = EvaluationOptions.DefaultOptions, }; options.EvaluationOptions.UseExternalTypeResolver = true; ClearAdbLogcat(); appBuilder.BuildLogFile = "run.log"; parameters.Add($"AndroidSdbTargetPort={port}"); parameters.Add($"AndroidSdbHostPort={port}"); parameters.Add("AndroidAttachDebugger=True"); Assert.True(appBuilder.RunTarget(app, "_Run", doNotCleanupOnUpdate: true, parameters: parameters.ToArray()), "Project should have run."); Assert.IsTrue(WaitForDebuggerToStart(Path.Combine(Root, appBuilder.ProjectDirectory, "logcat.log")), "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); }; session.OutputWriter += (isStderr, text) => { Console.WriteLine(text); }; session.DebugWriter += (level, category, message) => { Console.WriteLine(message); }; session.Run(startInfo, options); WaitFor(TimeSpan.FromSeconds(30), () => session.IsConnected); Assert.True(session.IsConnected, "Debugger should have connected but it did not."); // we need to wait here for a while to allow the breakpoints to hit // but we need to timeout TimeSpan timeout = TimeSpan.FromSeconds(60); int expected = 4; while (session.IsConnected && breakcountHitCount < 3 && timeout >= TimeSpan.Zero) { Thread.Sleep(10); timeout = timeout.Subtract(TimeSpan.FromMilliseconds(10)); } WaitFor(2000); Assert.AreEqual(expected, breakcountHitCount, $"Should have hit {expected} breakpoints. Only hit {breakcountHitCount}"); breakcountHitCount = 0; ClearAdbLogcat(); ClickButton(app.PackageName, "myXFButton", "CLICK ME"); while (session.IsConnected && breakcountHitCount < 1 && timeout >= TimeSpan.Zero) { Thread.Sleep(10); timeout = timeout.Subtract(TimeSpan.FromMilliseconds(10)); } expected = 1; Assert.AreEqual(expected, breakcountHitCount, $"Should have hit {expected} breakpoints. Only hit {breakcountHitCount}"); appBuilder.BuildLogFile = "uninstall.log"; Assert.True(appBuilder.Uninstall(app), "Project should have uninstalled."); session.Exit(); } }
public void ResolveLibraryProjectImports([Values(true, false)] bool useAapt2) { var proj = new XamarinFormsAndroidApplicationProject(); proj.SetProperty("AndroidUseAapt2", useAapt2.ToString()); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "first build should have succeeded."); var intermediate = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath); var cacheFile = Path.Combine(intermediate, "libraryprojectimports.cache"); FileAssert.Exists(cacheFile); var expected = ReadCache(cacheFile); Assert.AreNotEqual(0, expected.Jars.Length, $"{nameof (expected.Jars)} should not be empty"); Assert.AreNotEqual(0, expected.ResolvedResourceDirectories.Length, $"{nameof (expected.ResolvedResourceDirectories)} should not be empty"); Assert.AreNotEqual(0, expected.ResolvedResourceDirectoryStamps.Length, $"{nameof (expected.ResolvedResourceDirectoryStamps)} should not be empty"); // Delete the stamp file; this triggers <ResolveLibraryProjectImports/> to re-run. // However, the task will skip everything, since the hashes of each assembly will be the same. var stamp = Path.Combine(intermediate, "stamp", "_ResolveLibraryProjectImports.stamp"); FileAssert.Exists(stamp); File.Delete(stamp); Assert.IsTrue(b.Build(proj), "second build should have succeeded."); var actual = ReadCache(cacheFile); CollectionAssert.AreEqual(actual.Jars.Select(j => j.ItemSpec), expected.Jars.Select(j => j.ItemSpec)); CollectionAssert.AreEqual(actual.ResolvedResourceDirectories.Select(j => j.ItemSpec), expected.ResolvedResourceDirectories.Select(j => j.ItemSpec)); // Add a new AAR file to the project var aar = new AndroidItem.AndroidAarLibrary("Jars\\android-crop-1.0.1.aar") { WebContent = "https://jcenter.bintray.com/com/soundcloud/android/android-crop/1.0.1/android-crop-1.0.1.aar" }; proj.OtherBuildItems.Add(aar); Assert.IsTrue(b.Build(proj), "third build should have succeeded."); actual = ReadCache(cacheFile); Assert.AreEqual(expected.Jars.Length + 1, actual.Jars.Length, $"{nameof (expected.Jars)} should have one more item"); Assert.AreEqual(expected.ResolvedResourceDirectories.Length + 1, actual.ResolvedResourceDirectories.Length, $"{nameof (expected.ResolvedResourceDirectories)} should have one more item"); Assert.AreEqual(expected.ResolvedResourceDirectoryStamps.Length + 1, actual.ResolvedResourceDirectoryStamps.Length, $"{nameof (expected.ResolvedResourceDirectoryStamps)} should have one more item"); foreach (var s in actual.ResolvedResourceDirectoryStamps) { FileAssert.Exists(s.ItemSpec); } // Build with no changes, checking we are skipping targets appropriately Assert.IsTrue(b.Build(proj), "fourth build should have succeeded."); var targets = new List <string> { "_UpdateAndroidResgen", "_CompileJava", "_CreateBaseApk", }; if (useAapt2) { targets.Add("_ConvertLibraryResourcesCases"); } foreach (var targetName in targets) { Assert.IsTrue(b.Output.IsTargetSkipped(targetName), $"`{targetName}` should be skipped!"); } } }
public void ApplicationRunsWithDebuggerAndBreaks(bool useSharedRuntime, bool embedAssemblies, string fastDevType) { if (!CommercialBuildAvailable) { Assert.Ignore("Test does not run on the Open Source Builds."); return; } if (!HasDevices) { Assert.Ignore("Test needs a device attached."); return; } var proj = new XamarinFormsAndroidApplicationProject() { IsRelease = false, AndroidFastDeploymentType = fastDevType }; var abis = new string [] { "armeabi-v7a", "x86" }; proj.SetProperty(KnownProperties.AndroidSupportedAbis, string.Join(";", abis)); proj.SetProperty(KnownProperties.AndroidUseSharedRuntime, useSharedRuntime.ToString()); proj.SetProperty("EmbedAssembliesIntoApk", embedAssemblies.ToString()); proj.SetDefaultTargetDevice(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { string apiLevel; proj.TargetFrameworkVersion = b.LatestTargetFrameworkVersion(out apiLevel); proj.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""UnnamedProject.UnnamedProject""> <uses-sdk android:minSdkVersion=""24"" android:targetSdkVersion=""{apiLevel}"" /> <application android:label=""${{PROJECT_NAME}}""> </application > </manifest>"; b.Save(proj, saveProject: true); proj.NuGetRestore(Path.Combine(Root, b.ProjectDirectory), b.PackagesDirectory); Assert.True(b.Build(proj), "Project should have built."); Assert.True(b.Install(proj), "Project should have installed."); int breakcountHitCount = 0; ManualResetEvent resetEvent = new ManualResetEvent(false); var sw = new Stopwatch(); // setup the debugger var session = new SoftDebuggerSession(); session.Breakpoints = new BreakpointStore { { Path.Combine(Root, b.ProjectDirectory, "MainActivity.cs"), 19 }, { Path.Combine(Root, b.ProjectDirectory, "MainPage.xaml.cs"), 14 }, { Path.Combine(Root, b.ProjectDirectory, "MainPage.xaml.cs"), 19 }, { Path.Combine(Root, b.ProjectDirectory, "App.xaml.cs"), 12 }, }; session.TargetHitBreakpoint += (sender, e) => { Console.WriteLine($"BREAK {e.Type}"); breakcountHitCount++; session.Continue(); }; var rnd = new Random(); int port = rnd.Next(10000, 20000); TestContext.Out.WriteLine($"{port}"); var args = new SoftDebuggerConnectArgs("", IPAddress.Loopback, port) { MaxConnectionAttempts = 10, }; var startInfo = new SoftDebuggerStartInfo(args) { WorkingDirectory = Path.Combine(b.ProjectDirectory, proj.IntermediateOutputPath, "android", "assets"), }; var options = new DebuggerSessionOptions() { EvaluationOptions = EvaluationOptions.DefaultOptions, }; options.EvaluationOptions.UseExternalTypeResolver = true; ClearAdbLogcat(); Assert.True(b.RunTarget(proj, "_Run", parameters: new string [] { $"AndroidSdbTargetPort={port}", $"AndroidSdbHostPort={port}", "AndroidAttachDebugger=True", }), "Project should have run."); Assert.IsTrue(WaitForDebuggerToStart(output: out string logcat), "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); }; session.OutputWriter += (isStderr, text) => { Console.WriteLine(text); }; session.DebugWriter += (level, category, message) => { Console.WriteLine(message); }; session.Run(startInfo, options); WaitFor(TimeSpan.FromSeconds(30), () => session.IsConnected); Assert.True(session.IsConnected, "Debugger should have connected but it did not."); // we need to wait here for a while to allow the breakpoints to hit // but we need to timeout TimeSpan timeout = TimeSpan.FromSeconds(60); while (session.IsConnected && breakcountHitCount < 3) { Thread.Sleep(10); timeout = timeout.Subtract(TimeSpan.FromMilliseconds(10)); } WaitFor(2000); ClearAdbLogcat(); ClickButton(proj.PackageName, "myXFButton", "CLICK ME"); while (session.IsConnected && breakcountHitCount < 4) { Thread.Sleep(10); timeout = timeout.Subtract(TimeSpan.FromMilliseconds(10)); } int expected = 4; Assert.AreEqual(expected, breakcountHitCount, $"Should have hit {expected} breakpoints. Only hit {breakcountHitCount}"); Assert.True(b.Uninstall(proj), "Project should have uninstalled."); session.Exit(); } }