diff --git a/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/AddInSetupTests.cs b/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/AddInSetupTests.cs index 5742bb7e9f..23e8777817 100644 --- a/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/AddInSetupTests.cs +++ b/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/AddInSetupTests.cs @@ -43,6 +43,12 @@ namespace ICSharpCode.AddInManager2.Tests _addInSetup = new AddInSetup(_events, _nuGet, _sdAddInManagement); } + private void ClearAddInNuGetProperties(AddIn addIn) + { + addIn.Properties.Remove(ManagedAddIn.NuGetPackageIDManifestAttribute); + addIn.Properties.Remove(ManagedAddIn.NuGetPackageVersionManifestAttribute); + } + private void CreateAddIns() { // Create AddIn objects from *.addin files available in this assembly's output directory @@ -51,31 +57,37 @@ namespace ICSharpCode.AddInManager2.Tests using (StreamReader streamReader = new StreamReader(@"TestResources\AddInManager2Test.addin")) { _addIn1 = AddIn.Load(_addInTree, streamReader); + ClearAddInNuGetProperties(_addIn1); } using (StreamReader streamReader = new StreamReader(@"TestResources\AddInManager2Test_New.addin")) { _addIn1_new = AddIn.Load(_addInTree, streamReader); + ClearAddInNuGetProperties(_addIn1_new); } using (StreamReader streamReader = new StreamReader(@"TestResources\AddInManager2Test_2.addin")) { _addIn2 = AddIn.Load(_addInTree, streamReader); + ClearAddInNuGetProperties(_addIn2); } using (StreamReader streamReader = new StreamReader(@"TestResources\AddInManager2Test_2_New.addin")) { _addIn2_new = AddIn.Load(_addInTree, streamReader); + ClearAddInNuGetProperties(_addIn2_new); } using (StreamReader streamReader = new StreamReader(@"TestResources\AddInManager2Test_noIdentity.addin")) { _addIn_noIdentity = AddIn.Load(_addInTree, streamReader); + ClearAddInNuGetProperties(_addIn_noIdentity); } using (StreamReader streamReader = new StreamReader(@"TestResources\AddInManager2Test_noVersion.addin")) { _addIn_noVersion = AddIn.Load(_addInTree, streamReader); + ClearAddInNuGetProperties(_addIn_noVersion); } } @@ -702,6 +714,190 @@ namespace ICSharpCode.AddInManager2.Tests Assert.That(nuGetPackageUninstalled, Is.False, "Downloaded NuGet package should be uninstalled."); } + [Test, Description("AddIn installed from a NuGet package must be updated from an offline *.sdaddin file. Pending update must be cancellable.")] + public void UpdateAddInFromDownloadedNuGetPackageWithOfflineAddInAndCancel() + { + CreateAddIns(); + + // Create fake packages + FakePackage fakePackage = new FakePackage() + { + Id = _addIn1.Manifest.PrimaryIdentity, + Version = new SemanticVersion(_addIn1.Version) + }; + _addIn1.Properties[ManagedAddIn.NuGetPackageIDManifestAttribute] = _addIn1.Manifest.PrimaryIdentity; + _addIn1.Properties[ManagedAddIn.NuGetPackageVersionManifestAttribute] = _addIn1.Version.ToString(); + + // Prepare all (fake) services needed for AddInSetup and its instance, itself + PrepareAddInSetup(); + + // Prepare event handlers + bool addInInstalledEventReceived = false; + _events.AddInInstalled += delegate(object sender, AddInInstallationEventArgs e) + { + if (e.AddIn.Manifest.PrimaryIdentity == _addIn1_new.Manifest.PrimaryIdentity) + { + addInInstalledEventReceived = true; + } + }; + bool addInUninstalledEventReceived = false; + _events.AddInUninstalled += delegate(object sender, AddInInstallationEventArgs e) + { + if (e.AddIn.Manifest.PrimaryIdentity == _addIn1_new.Manifest.PrimaryIdentity) + { + addInUninstalledEventReceived = true; + } + }; + bool nuGetPackageUninstalled = false; + _nuGet.FakeCorePackageManager.UninstallPackageCallback = delegate(IPackage package, bool forceRemove, bool removeDependencies) + { + if ((package == fakePackage) && forceRemove && !removeDependencies) + { + nuGetPackageUninstalled = true; + } + }; + + // This AddIn is already installed + _sdAddInManagement.RegisteredAddIns.Add(_addIn1); + FakeCorePackageRepository localRepository = new FakeCorePackageRepository(); + _nuGet.FakeCorePackageManager.LocalRepository = localRepository; + localRepository.ReturnedPackages = (new IPackage[] { fakePackage }).AsQueryable(); + + // Install the new version of AddIn from manifest + _sdAddInManagement.AddInToLoad = _addIn1_new; + AddIn installedAddIn = _addInSetup.InstallAddIn(@"TestResources\AddInManager2Test_New.sdaddin"); + + // Test updated AddIn in AddInTree + Assert.That(installedAddIn, Is.Not.Null, "InstallAddIn() returns valid AddIn object"); + Assert.That(_sdAddInManagement.RegisteredAddIns, Contains.Item(_addIn1), "Old AddIn object still in AddInTree"); + Assert.That(_sdAddInManagement.RegisteredAddIns.Contains(_addIn1_new), Is.Not.True, + "New AddIn object not in AddInTree"); + + // Look if we find a ManagedAddIn object for the new AddIn + var foundAddIns = + _addInSetup.AddInsWithMarkedForInstallation.Where(ma => ma.AddIn.Manifest.PrimaryIdentity == _addIn1.Manifest.PrimaryIdentity); + + Assert.That(foundAddIns.Any(), "ManagedAddIn found in AddInsWithMarkedForInstallation"); + + var foundAddIn = foundAddIns.First(); + Assert.That(foundAddIn.AddIn.Version, Is.EqualTo(_addIn1_new.Version), "ManagedAddIn must have new version"); + Assert.That(foundAddIn.OldVersion, Is.EqualTo(_addIn1.Version), "ManagedAddIn must know installed (old) version"); + Assert.That(foundAddIn.IsTemporary, Is.True, "ManagedAddIn is temporary"); + Assert.That(foundAddIn.IsUpdate, Is.True, "ManagedAddIn is an update"); + Assert.That(foundAddIn.InstallationSource, Is.EqualTo(AddInInstallationSource.Offline), "ManagedAddIn's installation source is 'offline'"); + + Assert.That(addInInstalledEventReceived, "AddInInstalled event sent with correct AddIn"); + + // Cancel the update + _sdAddInManagement.TempInstallDirectory = ""; + _sdAddInManagement.UserInstallDirectory = ""; + _addInSetup.CancelUpdate(_addIn1_new); + + // Now check AddInTree, again + foundAddIns = + _addInSetup.AddInsWithMarkedForInstallation.Where(ma => ma.AddIn.Manifest.PrimaryIdentity == _addIn1.Manifest.PrimaryIdentity); + + Assert.That(foundAddIns.Any(), "ManagedAddIn still found in AddInsWithMarkedForInstallation after cancel"); + + foundAddIn = foundAddIns.First(); + Assert.That(foundAddIn.AddIn.Version, Is.EqualTo(_addIn1.Version), "ManagedAddIn now has old version"); + + Assert.That(addInUninstalledEventReceived, "AddInUninstalled event sent with correct AddIn"); + Assert.That(nuGetPackageUninstalled, Is.False, "Already installed NuGet package must not be removed."); + } + + [Test, Description("AddIn installed from a NuGet package must be updated from an offline *.sdaddin file with an older version. Pending update must be cancellable.")] + public void UpdateAddInFromDownloadedNuGetPackageWithOlderOfflineAddInAndCancel() + { + CreateAddIns(); + + // Create fake packages + FakePackage fakePackage = new FakePackage() + { + Id = _addIn1_new.Manifest.PrimaryIdentity, + Version = new SemanticVersion(_addIn1_new.Version) + }; + _addIn1_new.Properties[ManagedAddIn.NuGetPackageIDManifestAttribute] = _addIn1_new.Manifest.PrimaryIdentity; + _addIn1_new.Properties[ManagedAddIn.NuGetPackageVersionManifestAttribute] = _addIn1_new.Version.ToString(); + + // Prepare all (fake) services needed for AddInSetup and its instance, itself + PrepareAddInSetup(); + + // Prepare event handlers + bool addInInstalledEventReceived = false; + _events.AddInInstalled += delegate(object sender, AddInInstallationEventArgs e) + { + if (e.AddIn.Manifest.PrimaryIdentity == _addIn1_new.Manifest.PrimaryIdentity) + { + addInInstalledEventReceived = true; + } + }; + bool addInUninstalledEventReceived = false; + _events.AddInUninstalled += delegate(object sender, AddInInstallationEventArgs e) + { + if (e.AddIn.Manifest.PrimaryIdentity == _addIn1_new.Manifest.PrimaryIdentity) + { + addInUninstalledEventReceived = true; + } + }; + bool nuGetPackageUninstalled = false; + _nuGet.FakeCorePackageManager.UninstallPackageCallback = delegate(IPackage package, bool forceRemove, bool removeDependencies) + { + if ((package == fakePackage) && forceRemove && !removeDependencies) + { + nuGetPackageUninstalled = true; + } + }; + + // This AddIn is already installed + _sdAddInManagement.RegisteredAddIns.Add(_addIn1_new); + FakeCorePackageRepository localRepository = new FakeCorePackageRepository(); + _nuGet.FakeCorePackageManager.LocalRepository = localRepository; + localRepository.ReturnedPackages = (new IPackage[] { fakePackage }).AsQueryable(); + + // Install the new version of AddIn from manifest + _sdAddInManagement.AddInToLoad = _addIn1; + AddIn installedAddIn = _addInSetup.InstallAddIn(@"TestResources\AddInManager2Test.sdaddin"); + + // Test updated AddIn in AddInTree + Assert.That(installedAddIn, Is.Not.Null, "InstallAddIn() returns valid AddIn object"); + Assert.That(_sdAddInManagement.RegisteredAddIns, Contains.Item(_addIn1_new), "Old AddIn object still in AddInTree"); + Assert.That(_sdAddInManagement.RegisteredAddIns.Contains(_addIn1), Is.Not.True, + "New AddIn object not in AddInTree"); + + // Look if we find a ManagedAddIn object for the new AddIn + var foundAddIns = + _addInSetup.AddInsWithMarkedForInstallation.Where(ma => ma.AddIn.Manifest.PrimaryIdentity == _addIn1_new.Manifest.PrimaryIdentity); + + Assert.That(foundAddIns.Any(), "ManagedAddIn found in AddInsWithMarkedForInstallation"); + + var foundAddIn = foundAddIns.First(); + Assert.That(foundAddIn.AddIn.Version, Is.EqualTo(_addIn1.Version), "ManagedAddIn must have new version"); + Assert.That(foundAddIn.OldVersion, Is.EqualTo(_addIn1_new.Version), "ManagedAddIn must know installed (old) version"); + Assert.That(foundAddIn.IsTemporary, Is.True, "ManagedAddIn is temporary"); + Assert.That(foundAddIn.IsUpdate, Is.True, "ManagedAddIn is an update"); + Assert.That(foundAddIn.InstallationSource, Is.EqualTo(AddInInstallationSource.Offline), "ManagedAddIn's installation source is 'offline'"); + + Assert.That(addInInstalledEventReceived, "AddInInstalled event sent with correct AddIn"); + + // Cancel the update + _sdAddInManagement.TempInstallDirectory = ""; + _sdAddInManagement.UserInstallDirectory = ""; + _addInSetup.CancelUpdate(_addIn1); + + // Now check AddInTree, again + foundAddIns = + _addInSetup.AddInsWithMarkedForInstallation.Where(ma => ma.AddIn.Manifest.PrimaryIdentity == _addIn1_new.Manifest.PrimaryIdentity); + + Assert.That(foundAddIns.Any(), "ManagedAddIn still found in AddInsWithMarkedForInstallation after cancel"); + + foundAddIn = foundAddIns.First(); + Assert.That(foundAddIn.AddIn.Version, Is.EqualTo(_addIn1_new.Version), "ManagedAddIn now has old version"); + + Assert.That(addInUninstalledEventReceived, "AddInUninstalled event sent with correct AddIn"); + Assert.That(nuGetPackageUninstalled, Is.False, "Already installed NuGet package must not be removed."); + } + [Test, Description("External AddIn must be uninstalled. Pending uninstallation must be cancellable.")] public void UninstallValidAddInFromManifestAndCancel() { @@ -795,5 +991,118 @@ namespace ICSharpCode.AddInManager2.Tests Assert.That(nuGetPackageUninstalled, Is.True, "NuGet package must be removed after restart."); } + + [Test] + public void RemoveUnreferencedNuGetPackage() + { + CreateAddIns(); + + // Create a fake package + FakePackage fakePackage1 = new FakePackage() + { + Id = _addIn1.Manifest.PrimaryIdentity, + Version = new SemanticVersion(_addIn1.Version) + }; + _addIn1.Properties.Set(ManagedAddIn.NuGetPackageIDManifestAttribute, fakePackage1.Id); + _addIn1.Properties.Set(ManagedAddIn.NuGetPackageVersionManifestAttribute, fakePackage1.Version.ToString()); + FakePackage fakePackage1_new = new FakePackage() + { + Id = _addIn1_new.Manifest.PrimaryIdentity, + Version = new SemanticVersion(_addIn1_new.Version) + }; + _addIn1_new.Properties.Set(ManagedAddIn.NuGetPackageIDManifestAttribute, fakePackage1_new.Id); + _addIn1_new.Properties.Set(ManagedAddIn.NuGetPackageVersionManifestAttribute, fakePackage1_new.Version.ToString()); + FakePackage fakePackage2 = new FakePackage() + { + Id = _addIn2.Manifest.PrimaryIdentity, + Version = new SemanticVersion(_addIn2.Version) + }; + _addIn2.Properties.Set(ManagedAddIn.NuGetPackageIDManifestAttribute, fakePackage2.Id); + _addIn2.Properties.Set(ManagedAddIn.NuGetPackageVersionManifestAttribute, fakePackage2.Version.ToString()); + + // Prepare all (fake) services needed for AddInSetup and its instance, itself + PrepareAddInSetup(); + + // Simulate an installed AddIn, which is not related to installed NuGet package + _sdAddInManagement.TempInstallDirectory = ""; + _sdAddInManagement.UserInstallDirectory = ""; + + // Simulate the installed NuGet package in local repository + FakeCorePackageRepository localRepository = new FakeCorePackageRepository(); + _nuGet.FakeCorePackageManager.LocalRepository = localRepository; + bool nuGetPackageUninstalled = false; + IPackage packageForUninstallEvent = null; + _nuGet.FakeCorePackageManager.UninstallPackageCallback = delegate(IPackage package, bool forceRemove, bool removeDependencies) + { + if ((package == packageForUninstallEvent) && forceRemove && !removeDependencies) + { + nuGetPackageUninstalled = true; + } + }; + + // Case 1: AddIn of local NuGet package is completely same as installed + nuGetPackageUninstalled = false; + localRepository.ReturnedPackages = (new IPackage[] { fakePackage1 }).AsQueryable(); + packageForUninstallEvent = fakePackage1; + _sdAddInManagement.RegisteredAddIns.Clear(); + _sdAddInManagement.RegisteredAddIns.Add(_addIn1); + _addInSetup.RemoveUnreferencedNuGetPackages(); + Assert.That(nuGetPackageUninstalled, Is.False, "fakePackage1 must not be removed, because identical to installed."); + + // Case 2: AddIn of local NuGet package not installed at all + nuGetPackageUninstalled = false; + localRepository.ReturnedPackages = (new IPackage[] { fakePackage1 }).AsQueryable(); + packageForUninstallEvent = fakePackage1; + _sdAddInManagement.RegisteredAddIns.Clear(); + _sdAddInManagement.RegisteredAddIns.Add(_addIn2); + _addInSetup.RemoveUnreferencedNuGetPackages(); + Assert.That(nuGetPackageUninstalled, Is.True, "fakePackage1 must be removed, because unreferenced."); + + // Case 3a: AddIn of local NuGet package is older than the one installed + nuGetPackageUninstalled = false; + localRepository.ReturnedPackages = (new IPackage[] { fakePackage1 }).AsQueryable(); + packageForUninstallEvent = fakePackage1; + _sdAddInManagement.RegisteredAddIns.Clear(); + _sdAddInManagement.RegisteredAddIns.Add(_addIn1_new); + _addInSetup.RemoveUnreferencedNuGetPackages(); + Assert.That(nuGetPackageUninstalled, Is.False, "fakePackage1 must not be removed, because older but the only one."); + + // Case 3b: There exists a local NuGet package identical to installed AddIn and an older one + nuGetPackageUninstalled = false; + localRepository.ReturnedPackages = (new IPackage[] { fakePackage1, fakePackage1_new }).AsQueryable(); + packageForUninstallEvent = fakePackage1; + _sdAddInManagement.RegisteredAddIns.Clear(); + _sdAddInManagement.RegisteredAddIns.Add(_addIn1_new); + _addInSetup.RemoveUnreferencedNuGetPackages(); + Assert.That(nuGetPackageUninstalled, Is.True, "fakePackage1 must be removed, because older and a better fitting package exists."); + + // Case 4a: AddIn of local NuGet package is newer than the one installed + nuGetPackageUninstalled = false; + localRepository.ReturnedPackages = (new IPackage[] { fakePackage1_new }).AsQueryable(); + packageForUninstallEvent = fakePackage1_new; + _sdAddInManagement.RegisteredAddIns.Clear(); + _sdAddInManagement.RegisteredAddIns.Add(_addIn1); + _addInSetup.RemoveUnreferencedNuGetPackages(); + Assert.That(nuGetPackageUninstalled, Is.False, "fakePackage1_new must not be removed, because newer but the only one."); + + // Case 4b: There exists a local NuGet package identical to installed AddIn and a newer one + nuGetPackageUninstalled = false; + localRepository.ReturnedPackages = (new IPackage[] { fakePackage1, fakePackage1_new }).AsQueryable(); + packageForUninstallEvent = fakePackage1_new; + _sdAddInManagement.RegisteredAddIns.Clear(); + _sdAddInManagement.RegisteredAddIns.Add(_addIn1); + _addInSetup.RemoveUnreferencedNuGetPackages(); + Assert.That(nuGetPackageUninstalled, Is.True, "fakePackage1_new must be removed, because newer and a better fitting package exists."); + + // Case 5: Installed AddIn has no NuGet version tag in manifest, and there are two versions of local NuGet packages + nuGetPackageUninstalled = false; + _addIn1.Properties.Remove(ManagedAddIn.NuGetPackageVersionManifestAttribute); + localRepository.ReturnedPackages = (new IPackage[] { fakePackage1, fakePackage1_new }).AsQueryable(); + packageForUninstallEvent = fakePackage1; + _sdAddInManagement.RegisteredAddIns.Clear(); + _sdAddInManagement.RegisteredAddIns.Add(_addIn1); + _addInSetup.RemoveUnreferencedNuGetPackages(); + Assert.That(nuGetPackageUninstalled, Is.True, "fakePackage1 must be removed, only the latest package is left for AddIn without version info."); + } } } diff --git a/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/AvailableAddInsViewModelTests.cs b/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/AvailableAddInsViewModelTests.cs index 9d1fd91d7d..4fdaeea125 100644 --- a/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/AvailableAddInsViewModelTests.cs +++ b/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/AvailableAddInsViewModelTests.cs @@ -144,6 +144,81 @@ namespace ICSharpCode.AddInManager2.Tests Assert.That(viewModel.AddInPackages[1].IsExternallyReferenced, Is.False, "2nd AddIn must not be 'externally referenced'"); } + [Test] + public void ShowInstallableAddInsFromDifferentRepositories() + { + CreateAddIns(); + _addIn1.Enabled = true; + + // Package to be shown in repository + FakePackage fakePackage1 = new FakePackage() + { + Id = _addIn1.Manifest.PrimaryIdentity, + Version = new SemanticVersion(_addIn1.Version), + Tags = SharpDevelopAddInTag + }; + FakePackage fakePackage2 = new FakePackage() + { + Id = _addIn2.Manifest.PrimaryIdentity, + Version = new SemanticVersion(_addIn2.Version), + Tags = SharpDevelopAddInTag + }; + + // List of NuGet repositories + List registeredPackageSources = new List(); + registeredPackageSources.Add(new PackageSource("source1", "Test Repository 1")); + registeredPackageSources.Add(new PackageSource("source2", "Test Repository 2")); + _services.FakeRepositories.RegisteredPackageSources = registeredPackageSources; + + List registeredPackageRepositories = new List(); + FakeCorePackageRepository remoteRepository1 = new FakeCorePackageRepository(); + remoteRepository1.Source = registeredPackageSources[0].Source; + remoteRepository1.ReturnedPackages = (new IPackage[] { fakePackage1 }).AsQueryable(); + FakeCorePackageRepository remoteRepository2 = new FakeCorePackageRepository(); + remoteRepository2.Source = registeredPackageSources[1].Source; + remoteRepository2.ReturnedPackages = (new IPackage[] { fakePackage2 }).AsQueryable(); + _services.FakeRepositories.RegisteredPackageRepositories = registeredPackageRepositories; + + // PackageRepository service should return remoteRepository instance + _services.FakeRepositories.GetRepositoryFromSourceCallback = delegate(PackageSource packageSource) + { + if (packageSource.Source == remoteRepository1.Source) + { + return remoteRepository1; + } + else if (packageSource.Source == remoteRepository2.Source) + { + return remoteRepository2; + } + + return null; + }; + + FakeCorePackageRepository localRepository = new FakeCorePackageRepository(); + _services.FakeNuGet.FakeCorePackageManager.LocalRepository = localRepository; + localRepository.ReturnedPackages = (new IPackage[] { }).AsQueryable(); + + var viewModel = new AvailableAddInsViewModel(_services); + viewModel.ReadPackagesAndWaitForUpdate(); + + Assert.That(viewModel.AddInPackages.Count, Is.EqualTo(1), "AddIn list must contain 1 item."); + + AddInPackageViewModelBase firstAddIn = viewModel.AddInPackages[0]; + Assert.That(firstAddIn.Id, Is.EqualTo(_addIn1.Manifest.PrimaryIdentity), "Primary identity of 1st AddIn"); + Assert.That(firstAddIn.Name, Is.EqualTo(_addIn1.Manifest.PrimaryIdentity), "Name of 1st AddIn"); + Assert.That(firstAddIn.Version, Is.EqualTo(_addIn1.Version), "Version of 1st AddIn"); + + viewModel.SelectedPackageSource = viewModel.PackageRepositories[1]; + viewModel.ReadPackagesAndWaitForUpdate(); + + Assert.That(viewModel.AddInPackages.Count, Is.EqualTo(1), "AddIn list must contain 1 item."); + + AddInPackageViewModelBase secondAddIn = viewModel.AddInPackages[0]; + Assert.That(secondAddIn.Id, Is.EqualTo(_addIn2.Manifest.PrimaryIdentity), "Primary identity of 2nd AddIn"); + Assert.That(secondAddIn.Name, Is.EqualTo(_addIn2.Manifest.PrimaryIdentity), "Name of 2nd AddIn"); + Assert.That(secondAddIn.Version, Is.EqualTo(_addIn2.Version), "Version of 2nd AddIn"); + } + [Test] public void SearchInstallableAddIns() { @@ -248,6 +323,87 @@ namespace ICSharpCode.AddInManager2.Tests Assert.That(firstAddIn.Version, Is.EqualTo(_addIn2.Version), "Version of 1st AddIn"); } + [Test] + public void ShowInstallableAddInsWithPaging() + { + CreateAddIns(); + _addIn1.Enabled = true; + + // Packages to be shown in repository + FakePackage[] fakePackages = new FakePackage[35]; + for (int i = 0; i < fakePackages.Length; i++) + { + fakePackages[i] = new FakePackage() + { + Id = _addIn1.Manifest.PrimaryIdentity + i.ToString(), + Version = new SemanticVersion(_addIn1.Version), + Tags = SharpDevelopAddInTag + }; + } + + // List of NuGet repositories + List registeredPackageSources = new List(); + registeredPackageSources.Add(new PackageSource("", "Test Repository")); + _services.FakeRepositories.RegisteredPackageSources = registeredPackageSources; + + List registeredPackageRepositories = new List(); + FakeCorePackageRepository remoteRepository = new FakeCorePackageRepository(); + remoteRepository.Source = registeredPackageSources[0].Source; + remoteRepository.ReturnedPackages = fakePackages.AsQueryable(); + _services.FakeRepositories.RegisteredPackageRepositories = registeredPackageRepositories; + + // PackageRepository service should return remoteRepository instance + _services.FakeRepositories.GetRepositoryFromSourceCallback = delegate(PackageSource packageSource) + { + return remoteRepository; + }; + + FakeCorePackageRepository localRepository = new FakeCorePackageRepository(); + _services.FakeNuGet.FakeCorePackageManager.LocalRepository = localRepository; + localRepository.ReturnedPackages = (new IPackage[] { }).AsQueryable(); + + var viewModel = new AvailableAddInsViewModel(_services); + viewModel.ReadPackagesAndWaitForUpdate(); + + int itemsPerPage = 10; + int assumedPageCount = (fakePackages.Length / itemsPerPage) + 1; + Assert.That(viewModel.Pages.Count, Is.EqualTo(assumedPageCount), "There must be " + assumedPageCount + " pages"); + + // First page + Assert.That(viewModel.AddInPackages.Count, Is.EqualTo(itemsPerPage), "First page contains " + itemsPerPage + " AddIns."); + for (int i = 0; i < itemsPerPage; i++) + { + int realIndex = i; + AddInPackageViewModelBase firstAddIn = viewModel.AddInPackages[i]; + Assert.That(firstAddIn.Id, Is.EqualTo(fakePackages[realIndex].Id), "Primary identity of AddIn " + realIndex); + Assert.That(firstAddIn.Version, Is.EqualTo(fakePackages[realIndex].Version.Version), "Version of AddIn " + realIndex); + } + + viewModel.SetPageAndWaitForUpdate(2); + + // Second page + Assert.That(viewModel.AddInPackages.Count, Is.EqualTo(itemsPerPage), "Second page contains " + itemsPerPage + " AddIns."); + for (int i = 0; i < itemsPerPage; i++) + { + int realIndex = i + itemsPerPage; + AddInPackageViewModelBase firstAddIn = viewModel.AddInPackages[i]; + Assert.That(firstAddIn.Id, Is.EqualTo(fakePackages[realIndex].Id), "Primary identity of AddIn " + realIndex); + Assert.That(firstAddIn.Version, Is.EqualTo(fakePackages[realIndex].Version.Version), "Version of AddIn " + realIndex); + } + + viewModel.SetPageAndWaitForUpdate(3); + + // Third page + Assert.That(viewModel.AddInPackages.Count, Is.EqualTo(itemsPerPage), "Third page contains " + itemsPerPage + " AddIns."); + for (int i = 0; i < itemsPerPage; i++) + { + int realIndex = i + (itemsPerPage * 2); + AddInPackageViewModelBase firstAddIn = viewModel.AddInPackages[i]; + Assert.That(firstAddIn.Id, Is.EqualTo(fakePackages[realIndex].Id), "Primary identity of AddIn " + realIndex); + Assert.That(firstAddIn.Version, Is.EqualTo(fakePackages[realIndex].Version.Version), "Version of AddIn " + realIndex); + } + } + [Test] public void ShowAlreadyInstalledAddIns() { diff --git a/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/ViewModelTestingExtensions.cs b/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/ViewModelTestingExtensions.cs index 23cdb67787..585f727bf0 100644 --- a/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/ViewModelTestingExtensions.cs +++ b/src/AddIns/Misc/AddInManager2/AddInManager2.Tests/ViewModelTestingExtensions.cs @@ -23,5 +23,17 @@ namespace ICSharpCode.AddInManager2.Tests // Clean up viewModel.AddInsListUpdated -= addInsListUpdatedHandler; } + + internal static void SetPageAndWaitForUpdate(this AddInsViewModelBase viewModel, int page) + { + ManualResetEvent updateDone = new ManualResetEvent(false); + EventHandler addInsListUpdatedHandler = delegate { updateDone.Set(); }; + viewModel.AddInsListUpdated += addInsListUpdatedHandler; + viewModel.SelectedPageNumber = page; + updateDone.WaitOne(5000); + + // Clean up + viewModel.AddInsListUpdated -= addInsListUpdatedHandler; + } } } diff --git a/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj index bdcbd9ba89..a2f8b355fb 100644 --- a/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj +++ b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj @@ -186,7 +186,9 @@ - + + PagedResultsView.xaml + diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInSetup.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInSetup.cs index fcd54bbb9e..7554d400cc 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInSetup.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInSetup.cs @@ -263,6 +263,9 @@ namespace ICSharpCode.AddInManager2.Model new AddInLoadException(SD.ResourceService.GetString("AddInManager.AddInMustHaveIdentity")))); return null; } + + // Just for safety also patch the properties of AddIn object directly + PatchAddInProperties(addIn, package); // Try to find this AddIn in current registry string identity = addIn.Manifest.PrimaryIdentity; @@ -320,12 +323,14 @@ namespace ICSharpCode.AddInManager2.Model } // Mark this AddIn + ManagedAddIn foundAddInManaged = new ManagedAddIn(foundAddIn); ManagedAddIn markedAddIn = new ManagedAddIn(addIn) { InstallationSource = AddInInstallationSource.NuGetRepository, IsTemporary = true, IsUpdate = (foundAddIn != null), - OldVersion = (foundAddIn != null) ? foundAddIn.Version : null + OldVersion = (foundAddIn != null) ? + new Version(foundAddInManaged.LinkedNuGetPackageVersion ?? foundAddIn.Version.ToString()) : null }; _addInsMarkedForInstall.Add(markedAddIn); @@ -366,7 +371,7 @@ namespace ICSharpCode.AddInManager2.Model if (package.Version != null) { XmlAttribute nuGetPackageVersionAttribute = addInManifestDoc.CreateAttribute(ManagedAddIn.NuGetPackageVersionManifestAttribute); - nuGetPackageVersionAttribute.Value = package.Version.Version.ToString(); + nuGetPackageVersionAttribute.Value = package.Version.ToString(); addInManifestDoc.DocumentElement.Attributes.Append(nuGetPackageVersionAttribute); } addInManifestDoc.Save(addInManifestFile); @@ -379,6 +384,27 @@ namespace ICSharpCode.AddInManager2.Model } } + private bool PatchAddInProperties(AddIn addIn, IPackage package) + { + if ((addIn != null) && (package != null)) + { + if (!addIn.Properties.Contains(ManagedAddIn.NuGetPackageIDManifestAttribute)) + { + addIn.Properties.Set(ManagedAddIn.NuGetPackageIDManifestAttribute, package.Id); + } + if (!addIn.Properties.Contains(ManagedAddIn.NuGetPackageVersionManifestAttribute)) + { + addIn.Properties.Set(ManagedAddIn.NuGetPackageVersionManifestAttribute, package.Version.ToString()); + } + + return true; + } + else + { + return false; + } + } + private bool CopyAddInFromZip(AddIn addIn, string zipFile) { if ((addIn != null) && (addIn.Manifest != null)) @@ -452,7 +478,16 @@ namespace ICSharpCode.AddInManager2.Model IPackage addInPackage = GetNuGetPackageForAddIn(addIn, true); if (addInPackage != null) { - _nuGet.Packages.UninstallPackage(addInPackage, true, false); + // Only remove this package, if really the same version is installed + string nuGetVersionInManifest = null; + if (addIn.Properties.Contains(ManagedAddIn.NuGetPackageVersionManifestAttribute)) + { + nuGetVersionInManifest = addIn.Properties[ManagedAddIn.NuGetPackageVersionManifestAttribute]; + } + if (nuGetVersionInManifest == addInPackage.Version.ToString()) + { + _nuGet.Packages.UninstallPackage(addInPackage, true, false); + } } AddInInstallationEventArgs eventArgs = new AddInInstallationEventArgs(addIn); @@ -794,15 +829,35 @@ namespace ICSharpCode.AddInManager2.Model } else { - // Try to get the most recent (= with highest version) package for this AddIn - IPackage latestPackage = installedNuGetPackages + // Count NuGet packages with current ID + int allPackagesOfThisNuGetID = installedNuGetPackages .Where(p => p.Id == installedPackage.Id) - .OrderBy(p => p.Version) - .LastOrDefault(); - if (latestPackage.Version != installedPackage.Version) + .Count(); + + if (allPackagesOfThisNuGetID > 1) { - // This is not the most recent installed package for this AddIn -> remove it - removeThisPackage = true; + // Compare version of package with version of installed AddIn + if (addIn.Properties.Contains(ManagedAddIn.NuGetPackageVersionManifestAttribute)) + { + if (addIn.Properties[ManagedAddIn.NuGetPackageVersionManifestAttribute] != installedPackage.Version.ToString()) + { + // AddIn has a NuGet version tag in its manifest, but not this one + removeThisPackage = true; + } + } + else + { + // AddIn has no NuGet version tag, so simply leave the latest NuGet package and remove all others + IPackage latestPackage = installedNuGetPackages + .Where(p => p.Id == installedPackage.Id) + .OrderBy(p => p.Version) + .LastOrDefault(); + if (latestPackage.Version != installedPackage.Version) + { + // This is not the most recent installed package for this AddIn -> remove it + removeThisPackage = true; + } + } } } diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetPackageViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetPackageViewModel.cs index 5dfd476bb0..9e1bb10a88 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetPackageViewModel.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetPackageViewModel.cs @@ -255,7 +255,14 @@ namespace ICSharpCode.AddInManager2.ViewModel { get { - return _package.Version.Version; + if (_package.Version != null) + { + return new Version(_package.Version.ToString()); + } + else + { + return null; + } } } @@ -266,7 +273,14 @@ namespace ICSharpCode.AddInManager2.ViewModel AddIn installedAddIn = AddInManager.Setup.GetAddInForNuGetPackage(_package); if ((installedAddIn != null) && IsUpdate) { - return installedAddIn.Version; + if (installedAddIn.Properties.Contains(ManagedAddIn.NuGetPackageVersionManifestAttribute)) + { + return new Version(installedAddIn.Properties[ManagedAddIn.NuGetPackageVersionManifestAttribute]); + } + else + { + return installedAddIn.Version; + } } else {