diff --git a/tests/BaGet.Core.Tests/BaGet.Core.Tests.csproj b/tests/BaGet.Core.Tests/BaGet.Core.Tests.csproj index f8cc9aa8..6c683d37 100644 --- a/tests/BaGet.Core.Tests/BaGet.Core.Tests.csproj +++ b/tests/BaGet.Core.Tests/BaGet.Core.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/tests/BaGet.Core.Tests/FilePackageStorageServiceTests.cs b/tests/BaGet.Core.Tests/FilePackageStorageServiceTests.cs deleted file mode 100644 index 758d2bba..00000000 --- a/tests/BaGet.Core.Tests/FilePackageStorageServiceTests.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.IO; -using BaGet.Core.Services; -using Xunit; - -namespace BaGet.Core.Tests -{ - public class FilePackageStorageServiceTests - { - [Fact] - public void CreatesStoreDirectoryIfItDoesNotExist() - { - string validButNotExistingPath = Path.Combine(Path.GetTempPath(), System.Guid.NewGuid().ToString("N")); - Assert.False(Directory.Exists(validButNotExistingPath)); - IPackageStorageService service = new FilePackageStorageService(validButNotExistingPath); - Assert.False(Directory.Exists(validButNotExistingPath)); - } - } -} diff --git a/tests/BaGet.Core.Tests/Services/FilePackageStorageServiceTests.cs b/tests/BaGet.Core.Tests/Services/FilePackageStorageServiceTests.cs new file mode 100644 index 00000000..fc6aad67 --- /dev/null +++ b/tests/BaGet.Core.Tests/Services/FilePackageStorageServiceTests.cs @@ -0,0 +1,141 @@ +using System.IO; +using System.Threading.Tasks; +using BaGet.Core.Services; +using Xunit; + +namespace BaGet.Core.Tests.Services +{ + public class FilePackageStorageServiceTests + { + public class SavePackageContentAsync : FactsBase + { + [Fact] + public async Task ThrowsIfPackageStreamIsNull() + { + await Task.Yield(); + } + + [Fact] + public async Task ThrowsIfNuspecStreamIsNull() + { + await Task.Yield(); + } + + [Fact] + public async Task DoesNotThrowIfReadmeStreamIsNull() + { + await Task.Yield(); + } + + [Fact] + public async Task SavesContent() + { + // TODO: Should lowercase id/version + // TODO: Should normalize version + // TODO: Test that a directory was created for the package + // TODO: Verify content. + await Task.Yield(); + } + + [Fact] + public async Task DoesNotThrowIfContentAlreadyExistsAndContentsMatch() + { + await Task.Yield(); + } + + [Fact] + public async Task ThrowsIfContentAlreadyExistsButContentsDoNotMatch() + { + await Task.Yield(); + } + } + + public class GetPackageStreamAsync : FactsBase + { + [Fact] + public async Task ThrowsIfDoesntExist() + { + await Task.Yield(); + } + + [Fact] + public async Task GetsStream() + { + // TODO: Should lowercase id/version + // TODO: Should normalize version + await Task.Yield(); + } + } + + public class GetNuspecStreamAsync : FactsBase + { + [Fact] + public async Task ThrowsIfDoesntExist() + { + await Task.Yield(); + } + + [Fact] + public async Task GetsStream() + { + // TODO: Should lowercase id/version + // TODO: Should normalize version + await Task.Yield(); + } + } + + public class GetReadmeStreamAsync : FactsBase + { + [Fact] + public async Task ThrowsIfDoesntExist() + { + await Task.Yield(); + } + + [Fact] + public async Task GetsStream() + { + // TODO: Should lowercase id/version + // TODO: Should normalize version + await Task.Yield(); + } + } + + public class DeleteAsync : FactsBase + { + [Fact] + public async Task DoesNotThrowIfPackagePathDoesNotExist() + { + await Task.Yield(); + } + + [Theory] + [InlineData(false, false, false)] + [InlineData(false, false, true)] + [InlineData(false, true, false)] + [InlineData(false, true, true)] + [InlineData(true, false, false)] + [InlineData(true, false, true)] + [InlineData(true, true, false)] + [InlineData(true, true, true)] + public async Task DeletesAnyExistingContent(bool packageExists, bool nuspecExists, bool readmeExists) + { + // TODO: Should lowercase id/version + // TODO: Should normalize version + await Task.Yield(); + } + } + + public class FactsBase + { + protected readonly string _storePath; + protected readonly FilePackageStorageService _target; + + public FactsBase() + { + _storePath = Path.Combine(Path.GetTempPath(), System.Guid.NewGuid().ToString("N")); + _target = new FilePackageStorageService(_storePath); + } + } + } +} diff --git a/tests/BaGet.Core.Tests/Services/IndexingServiceTests.cs b/tests/BaGet.Core.Tests/Services/IndexingServiceTests.cs new file mode 100644 index 00000000..985b2a3f --- /dev/null +++ b/tests/BaGet.Core.Tests/Services/IndexingServiceTests.cs @@ -0,0 +1,61 @@ +using System.Threading.Tasks; +using BaGet.Core.Services; +using Microsoft.Extensions.Logging; +using Moq; +using Xunit; + +namespace BaGet.Core.Tests.Services +{ + public class IndexingServiceTests + { + private readonly Mock _packages; + private readonly Mock _storage; + private readonly Mock _search; + private readonly IndexingService _target; + + public IndexingServiceTests() + { + _packages = new Mock(); + _storage = new Mock(); + _search = new Mock(); + + _target = new IndexingService( + _packages.Object, + _storage.Object, + _search.Object, + Mock.Of>()); + } + + // TODO: Add malformed package tests + + [Fact] + public async Task WhenPackageAlreadyExists_ReturnsPackageAlreadyExists() + { + await Task.Yield(); + } + + [Fact] + public async Task WhenDatabaseAddFailsBecausePackageAlreadyExists_ReturnsPackageAlreadyExists() + { + await Task.Yield(); + } + + [Fact] + public async Task IndexesPackage() + { + await Task.Yield(); + } + + [Fact] + public async Task WhenPackageHasNoReadme_SavesNullReadmeStream() + { + await Task.Yield(); + } + + [Fact] + public async Task ThrowsWhenStorageSaveThrows() + { + await Task.Yield(); + } + } +} diff --git a/tests/BaGet.Core.Tests/Services/PackageDeletionServiceTests.cs b/tests/BaGet.Core.Tests/Services/PackageDeletionServiceTests.cs new file mode 100644 index 00000000..944dd2b5 --- /dev/null +++ b/tests/BaGet.Core.Tests/Services/PackageDeletionServiceTests.cs @@ -0,0 +1,53 @@ +using System.Threading.Tasks; +using BaGet.Core.Configuration; +using BaGet.Core.Services; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using Xunit; + +namespace BaGet.Core.Tests.Services +{ + public class PackageDeletionServiceTests + { + private readonly Mock _packages; + private readonly Mock _storage; + + private readonly BaGetOptions _options; + private readonly PackageDeletionService _target; + + public PackageDeletionServiceTests() + { + _packages = new Mock(); + _storage = new Mock(); + _options = new BaGetOptions(); + + var optionsSnapshot = new Mock>(); + optionsSnapshot.Setup(o => o.Value).Returns(_options); + + _target = new PackageDeletionService( + _packages.Object, + _storage.Object, + optionsSnapshot.Object, + Mock.Of>()); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task WhenUnlist_ReturnsTrueOnlyIfPackageExists(bool packageExists) + { + await Task.Yield(); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + + public async Task WhenHardDelete_ReturnsTrueOnlyIfPackageExists(bool packageExists) + { + // TODO: Test that hard delete ALWAYS removes from storage, regardless of packageExists + await Task.Yield(); + } + } +} diff --git a/tests/BaGet.Core.Tests/Services/PackageServiceTests.cs b/tests/BaGet.Core.Tests/Services/PackageServiceTests.cs new file mode 100644 index 00000000..7b0a09f3 --- /dev/null +++ b/tests/BaGet.Core.Tests/Services/PackageServiceTests.cs @@ -0,0 +1,201 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using BaGet.Core.Entities; +using BaGet.Core.Services; +using Moq; +using Xunit; + +namespace BaGet.Core.Tests.Services +{ + public class PackageServiceTests + { + public class AddAsync : FactsBase + { + [Fact] + public async Task ReturnsPackageAlreadyExistsOnUniqueConstraintViolation() + { + await Task.Yield(); + } + + [Fact] + public async Task AddsPackage() + { + // TODO: Returns Success + // TODO: Adds package + await Task.Yield(); + } + } + + public class ExistsAsync : FactsBase + { + [Theory] + [InlineData("Package", "1.0.0", true)] + [InlineData("Package", "1.0.0.0", true)] + [InlineData("Unlisted.Package", "1.0.0", true)] + [InlineData("Fake.Package", "1.0.0", false)] + public async Task ReturnsTrueIfPackageExists(string packageId, string packageVersion, bool exists) + { + await Task.Yield(); + } + } + + public class FindAsync : FactsBase + { + [Fact] + public async Task ReturnsEmptyListIfPackageDoesNotExist() + { + // Ensure the context has packages with a different id/version + await Task.Yield(); + } + + [Theory] + [MemberData(nameof(ReturnsPackagesData))] + public async Task ReturnsPackages(string packageId, string packageVersion, bool includeUnlisted, bool exists) + { + // TODO: Ensure resulting versions are normalized. + await Task.Yield(); + } + + public static IEnumerable ReturnsPackagesData() + { + object[] ReturnsPackagesHelper(string packageId, string packageVersion, bool includeUnlisted, bool exists) + { + return new object[] { packageId, packageVersion, includeUnlisted, exists }; + } + + // A package that doesn't exist should never be returned + yield return ReturnsPackagesHelper("Fake.Package", "1.0.0", includeUnlisted: true, exists: false); + + // A listed package should be returned regardless of the "includeUnlisted" parameter + yield return ReturnsPackagesHelper("Package", "1.0.0", includeUnlisted: false, exists: true); + yield return ReturnsPackagesHelper("Package", "1.0.0", includeUnlisted: true, exists: true); + + // The inputted package version should be normalized + yield return ReturnsPackagesHelper("Package", "1.0.0.0", includeUnlisted: false, exists: true); + + // Unlisted packages should only be returned if "includeUnlisted" is true + yield return ReturnsPackagesHelper("Unlisted.Package", "1.0.0", includeUnlisted: false, exists: false); + yield return ReturnsPackagesHelper("Unlisted.Package", "1.0.0", includeUnlisted: true, exists: true); + } + } + + public class FindOrNullAsync : FactsBase + { + [Fact] + public async Task ReturnsNullIfPackageDoesNotExist() + { + await Task.Yield(); + } + + [Theory] + [MemberData(nameof(ReturnsPackageData))] + public async Task ReturnsPackage(string packageId, string packageVersion, bool includeUnlisted, bool exists) + { + // TODO: Ensure resulting versions are normalized. + await Task.Yield(); + } + + public static IEnumerable ReturnsPackageData() + { + object[] ReturnsPackageHelper(string packageId, string packageVersion, bool includeUnlisted, bool exists) + { + return new object[] { packageId, packageVersion, includeUnlisted, exists }; + } + + // A package that doesn't exist should never be returned + yield return ReturnsPackageHelper("Fake.Package", "1.0.0", includeUnlisted: true, exists: false); + + // A listed package should be returned regardless of the "includeUnlisted" parameter + yield return ReturnsPackageHelper("Package", "1.0.0", includeUnlisted: false, exists: true); + yield return ReturnsPackageHelper("Package", "1.0.0", includeUnlisted: true, exists: true); + + // The inputted package version should be normalized + yield return ReturnsPackageHelper("Package", "1.0.0.0", includeUnlisted: false, exists: true); + + // Unlisted packages should only be returned if "includeUnlisted" is true + yield return ReturnsPackageHelper("Unlisted.Package", "1.0.0", includeUnlisted: false, exists: false); + yield return ReturnsPackageHelper("Unlisted.Package", "1.0.0", includeUnlisted: true, exists: true); + } + } + + public class UnlistPackageAsync : FactsBase + { + [Fact] + public async Task ReturnsFalseIfPackageDoesNotExist() + { + await Task.Yield(); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task UnlistsPackage(bool listed) + { + // TODO: This should succeed if the package is unlisted. + // TODO: Returns true + await Task.Yield(); + } + } + + public class RelistPackageAsync : FactsBase + { + [Fact] + public async Task ReturnsFalseIfPackageDoesNotExist() + { + await Task.Yield(); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task RelistsPackage(bool listed) + { + // TODO: This should succeed if the package is listed. + // TODO: Return true + await Task.Yield(); + } + } + + public class AddDownloadAsync : FactsBase + { + [Fact] + public async Task ReturnsFalseIfPackageDoesNotExist() + { + await Task.Yield(); + } + + [Fact] + public async Task IncrementsPackageDownloads() + { + await Task.Yield(); + } + } + + public class HardDeletePackageAsync : FactsBase + { + [Fact] + public async Task ReturnsFalseIfPackageDoesNotExist() + { + await Task.Yield(); + } + + [Fact] + public async Task DeletesPackage() + { + await Task.Yield(); + } + } + + public class FactsBase + { + protected readonly Mock _context; + protected readonly PackageService _target; + + public FactsBase() + { + _context = new Mock(); + _target = new PackageService(_context.Object); + } + } + } +}