Skip to content

Commit

Permalink
Add throw helpers and tests (bagetter#74)
Browse files Browse the repository at this point in the history
* - add more tests
- update dependencies

* - more tests
- formatting

* format after merge with `main`

* more tests

* use file-scoped namespace

* update xunit

* adjust to review feedback

* review feedback
  • Loading branch information
FroggieFrog authored Mar 1, 2024
1 parent bebc997 commit 0700615
Show file tree
Hide file tree
Showing 32 changed files with 630 additions and 120 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = file_scoped:warning
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_prefer_primary_constructors = false:suggestion
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
Expand Down
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageVersion Include="Moq" Version="4.20.70" />
<PackageVersion Include="xunit" Version="2.6.6" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.6" />
<PackageVersion Include="xunit" Version="2.7.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.7" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
<PackageVersion Include="Humanizer" Version="2.14.1" />
Expand Down
3 changes: 2 additions & 1 deletion src/BaGetter.Core/Metadata/BaGetterPackageMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ namespace BaGetter.Core;
/// <summary>
/// BaGetter's extensions to the package metadata model.
/// </summary>
/// <remarks><para>Extends <see cref="PackageMetadata"/>.</para>
/// <remarks>
/// Extends <see cref="PackageMetadata"/>.<br/>
/// These additions are not part of the official protocol.
/// </remarks>
public class BaGetterPackageMetadata : PackageMetadata
Expand Down
24 changes: 11 additions & 13 deletions src/BaGetter.Core/Metadata/DefaultPackageMetadataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@

namespace BaGetter.Core;

/// <inheritdoc />
/// <inheritdoc/>
public class DefaultPackageMetadataService : IPackageMetadataService
{
private readonly IPackageService _packages;
private readonly RegistrationBuilder _builder;

public DefaultPackageMetadataService(
IPackageService packages,
RegistrationBuilder builder)
public DefaultPackageMetadataService(IPackageService packages, RegistrationBuilder builder)
{
_packages = packages ?? throw new ArgumentNullException(nameof(packages));
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
ArgumentNullException.ThrowIfNull(packages);
ArgumentNullException.ThrowIfNull(builder);

_packages = packages;
_builder = builder;
}

public async Task<BaGetterRegistrationIndexResponse> GetRegistrationIndexOrNullAsync(
string packageId,
CancellationToken cancellationToken = default)
/// <inheritdoc/>
public async Task<BaGetterRegistrationIndexResponse> GetRegistrationIndexOrNullAsync(string packageId, CancellationToken cancellationToken = default)
{
var packages = await _packages.FindPackagesAsync(packageId, cancellationToken);
if (!packages.Any())
Expand All @@ -37,10 +37,8 @@ public async Task<BaGetterRegistrationIndexResponse> GetRegistrationIndexOrNullA
packages));
}

public async Task<RegistrationLeafResponse> GetRegistrationLeafOrNullAsync(
string id,
NuGetVersion version,
CancellationToken cancellationToken = default)
/// <inheritdoc/>
public async Task<RegistrationLeafResponse> GetRegistrationLeafOrNullAsync(string id, NuGetVersion version, CancellationToken cancellationToken = default)
{
var package = await _packages.FindPackageOrNullAsync(id, version, cancellationToken);
if (package == null)
Expand Down
14 changes: 5 additions & 9 deletions src/BaGetter.Core/Metadata/IPackageMetadataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@ namespace BaGetter.Core;

/// <summary>
/// The Package Metadata client, used to fetch packages' metadata.
///
/// See https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource
/// </summary>
/// <remarks>See: <see href="https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource"/></remarks>
public interface IPackageMetadataService
{
/// <summary>
/// Attempt to get a package's registration index, if it exists.
/// See: https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#registration-page
/// </summary>
/// <remarks>See: <see href="https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#registration-page"/></remarks>
/// <param name="packageId">The package's ID.</param>
/// <param name="cancellationToken">A token to cancel the task.</param>
/// <returns>The package's registration index, or null if the package does not exist</returns>
/// <returns>The package's <see cref="BaGetterRegistrationIndexResponse">registration index</see>, or <see langword="null"/> if the package does not exist.</returns>
Task<BaGetterRegistrationIndexResponse> GetRegistrationIndexOrNullAsync(string packageId, CancellationToken cancellationToken = default);

/// <summary>
Expand All @@ -27,9 +26,6 @@ public interface IPackageMetadataService
/// <param name="packageId">The package's id.</param>
/// <param name="packageVersion">The package's version.</param>
/// <param name="cancellationToken">A token to cancel the task.</param>
/// <returns>The registration leaf, or null if the package does not exist.</returns>
Task<RegistrationLeafResponse> GetRegistrationLeafOrNullAsync(
string packageId,
NuGetVersion packageVersion,
CancellationToken cancellationToken = default);
/// <returns>The <see cref="RegistrationLeafResponse">registration leaf</see>, or <see langword="null"/> if the package does not exist.</returns>
Task<RegistrationLeafResponse> GetRegistrationLeafOrNullAsync(string packageId, NuGetVersion packageVersion, CancellationToken cancellationToken = default);
}
11 changes: 6 additions & 5 deletions src/BaGetter.Core/Metadata/PackageRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ public class PackageRegistration
/// </summary>
/// <param name="packageId"></param>
/// <param name="packages">All versions of the package.</param>
public PackageRegistration(
string packageId,
IReadOnlyList<Package> packages)
public PackageRegistration(string packageId, IReadOnlyList<Package> packages)
{
PackageId = packageId ?? throw new ArgumentNullException(nameof(packageId));
Packages = packages ?? throw new ArgumentNullException(nameof(packages));
ArgumentException.ThrowIfNullOrWhiteSpace(packageId);
ArgumentNullException.ThrowIfNull(packages);

PackageId = packageId;
Packages = packages;
}

/// <summary>
Expand Down
6 changes: 5 additions & 1 deletion src/BaGetter.Core/Metadata/RegistrationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ public class RegistrationBuilder

public RegistrationBuilder(IUrlGenerator url)
{
_url = url ?? throw new ArgumentNullException(nameof(url));
ArgumentNullException.ThrowIfNull(url);

_url = url;
}

public virtual BaGetterRegistrationIndexResponse BuildIndex(PackageRegistration registration)
{
ArgumentNullException.ThrowIfNull(registration);

var sortedPackages = registration.Packages.OrderBy(p => p.Version).ToList();

// TODO: Paging of registration items.
Expand Down
2 changes: 1 addition & 1 deletion src/BaGetter.Core/Search/AutocompleteRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ namespace BaGetter.Core;

/// <summary>
/// The NuGet V3 search request.
/// See: https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource#request-parameters
/// </summary>
/// <remarks>See: <see href="https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource#request-parameters"/></remarks>
public class AutocompleteRequest
{
/// <summary>
Expand Down
25 changes: 11 additions & 14 deletions src/BaGetter.Core/Search/DatabaseSearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@ public class DatabaseSearchService : ISearchService
private readonly IFrameworkCompatibilityService _frameworks;
private readonly ISearchResponseBuilder _searchBuilder;

public DatabaseSearchService(
IContext context,
IFrameworkCompatibilityService frameworks,
ISearchResponseBuilder searchBuilder)
public DatabaseSearchService(IContext context, IFrameworkCompatibilityService frameworks, ISearchResponseBuilder searchBuilder)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_frameworks = frameworks ?? throw new ArgumentNullException(nameof(frameworks));
_searchBuilder = searchBuilder ?? throw new ArgumentNullException(nameof(searchBuilder));
ArgumentNullException.ThrowIfNull(context);
ArgumentNullException.ThrowIfNull(frameworks);
ArgumentNullException.ThrowIfNull(searchBuilder);

_context = context;
_frameworks = frameworks;
_searchBuilder = searchBuilder;
}

public async Task<SearchResponse> SearchAsync(SearchRequest request, CancellationToken cancellationToken)
public async Task<SearchResponse> SearchAsync(SearchRequest request, CancellationToken cancellationToken)
{
var frameworks = GetCompatibleFrameworksOrNull(request.Framework);

Expand Down Expand Up @@ -77,9 +78,7 @@ public async Task<SearchResponse> SearchAsync(SearchRequest request, Cancellati
return _searchBuilder.BuildSearch(groupedResults);
}

public async Task<AutocompleteResponse> AutocompleteAsync(
AutocompleteRequest request,
CancellationToken cancellationToken)
public async Task<AutocompleteResponse> AutocompleteAsync(AutocompleteRequest request, CancellationToken cancellationToken)
{
IQueryable<Package> search = _context.Packages;

Expand All @@ -102,9 +101,7 @@ public async Task<AutocompleteResponse> AutocompleteAsync(
return _searchBuilder.BuildAutocomplete(packageIds);
}

public async Task<AutocompleteResponse> ListPackageVersionsAsync(
VersionsRequest request,
CancellationToken cancellationToken)
public async Task<AutocompleteResponse> ListPackageVersionsAsync(VersionsRequest request, CancellationToken cancellationToken)
{
var packageId = request.PackageId.ToLower();
var search = _context
Expand Down
2 changes: 1 addition & 1 deletion src/BaGetter.Core/Search/ISearchResponseBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using BaGetter.Protocol.Models;

namespace BaGetter.Core;
Expand Down
13 changes: 5 additions & 8 deletions src/BaGetter.Core/Search/ISearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,32 @@ namespace BaGetter.Core;

/// <summary>
/// The service used to search for packages.
///
/// See https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource
/// </summary>
/// <remarks>See: <see href="https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource"/></remarks>
public interface ISearchService
{
/// <summary>
/// Perform a search query.
/// See: https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-for-packages
/// </summary>
/// <remarks>See: <see href="https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-for-packages"/></remarks>
/// <param name="request">The search request.</param>
/// <param name="cancellationToken">A token to cancel the task.</param>
/// <returns>The search response.</returns>
Task<SearchResponse> SearchAsync(SearchRequest request, CancellationToken cancellationToken);

/// <summary>
/// Perform an autocomplete query.
/// See: https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource#search-for-package-ids
/// </summary>
/// <remarks>See: <see href="https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource#search-for-package-ids"/></remarks>
/// <param name="request">The autocomplete request.</param>
/// <param name="cancellationToken">A token to cancel the task.</param>
/// <returns>The autocomplete response.</returns>
Task<AutocompleteResponse> AutocompleteAsync(AutocompleteRequest request, CancellationToken cancellationToken);

/// <summary>
/// Enumerate listed package versions.
/// See: https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource#enumerate-package-versions
/// </summary>
/// <remarks>See: <see href="https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource#enumerate-package-versions"/></remarks>
/// <param name="request">The autocomplete request.</param>
/// <param name="cancellationToken">A token to cancel the task.</param>
/// <returns>The package versions that matched the request.</returns>
Expand All @@ -44,7 +43,5 @@ public interface ISearchService
/// <param name="packageId">The package whose dependents should be found.</param>
/// <param name="cancellationToken">A token to cancel the task.</param>
/// <returns>The dependents response.</returns>
Task<DependentsResponse> FindDependentsAsync(
string packageId,
CancellationToken cancellationToken);
Task<DependentsResponse> FindDependentsAsync(string packageId, CancellationToken cancellationToken);
}
2 changes: 1 addition & 1 deletion src/BaGetter.Core/Search/SearchRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ namespace BaGetter.Core;

/// <summary>
/// The NuGet V3 search request.
/// See: https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#request-parameters
/// </summary>
/// <remarks>See: <see href="https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#request-parameters"/></remarks>
public class SearchRequest
{
/// <summary>
Expand Down
6 changes: 4 additions & 2 deletions src/BaGetter.Core/Search/SearchResponseBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using BaGetter.Protocol.Models;
Expand All @@ -11,7 +11,9 @@ public class SearchResponseBuilder : ISearchResponseBuilder

public SearchResponseBuilder(IUrlGenerator url)
{
_url = url ?? throw new ArgumentNullException(nameof(url));
ArgumentNullException.ThrowIfNull(url);

_url = url;
}

public SearchResponse BuildSearch(IReadOnlyList<PackageRegistration> packageRegistrations)
Expand Down
8 changes: 4 additions & 4 deletions src/BaGetter.Core/Storage/IStorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ namespace BaGetter.Core;
/// </summary>
/// <remarks>
/// This is used to store:
///
/// * Packages, through <see cref="PackageStorageService"/>
/// * Symbols, through <see cref="SymbolStorageService"/>
///
/// <list type="bullet">
/// <item>Packages, through <see cref="PackageStorageService"/></item>
/// <item>Symbols, through <see cref="SymbolStorageService"/></item>
/// </list>
/// This storage abstraction has implementations for disk,
/// Azure Blob Storage, Amazon Web Services S3, and Google Cloud Storage.
/// </remarks>
Expand Down
7 changes: 5 additions & 2 deletions src/BaGetter.Core/Upstream/Clients/V3UpstreamClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ public class V3UpstreamClient : IUpstreamClient

public V3UpstreamClient(NuGetClient client, ILogger<V3UpstreamClient> logger)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
ArgumentNullException.ThrowIfNull(client);
ArgumentNullException.ThrowIfNull(logger);

_client = client;
_logger = logger;
}

public async Task<Stream> DownloadPackageOrNullAsync(
Expand Down
10 changes: 7 additions & 3 deletions src/BaGetter.Core/Upstream/DownloadsImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ public DownloadsImporter(
IPackageDownloadsSource downloadsSource,
ILogger<DownloadsImporter> logger)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_downloadsSource = downloadsSource ?? throw new ArgumentNullException(nameof(downloadsSource));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
ArgumentNullException.ThrowIfNull(context);
ArgumentNullException.ThrowIfNull(downloadsSource);
ArgumentNullException.ThrowIfNull(logger);

_context = context;
_downloadsSource = downloadsSource;
_logger = logger;
}

public async Task ImportAsync(CancellationToken cancellationToken)
Expand Down
9 changes: 6 additions & 3 deletions src/BaGetter.Core/Upstream/PackageDownloadsJsonSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace BaGetter.Core;

// See https://github.com/NuGet/NuGet.Services.Metadata/blob/master/src/NuGet.Indexing/Downloads.cs
/// <remarks>See: <see href="https://github.com/NuGet/NuGet.Services.Metadata/blob/master/src/NuGet.Indexing/Downloads.cs"/></remarks>
public class PackageDownloadsJsonSource : IPackageDownloadsSource
{
public const string PackageDownloadsV1Url = "https://nugetprod0.blob.core.windows.net/ng-search-data/downloads.v1.json";
Expand All @@ -21,8 +21,11 @@ public class PackageDownloadsJsonSource : IPackageDownloadsSource

public PackageDownloadsJsonSource(HttpClient httpClient, ILogger<PackageDownloadsJsonSource> logger)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
ArgumentNullException.ThrowIfNull(httpClient);
ArgumentNullException.ThrowIfNull(logger);

_httpClient = httpClient;
_logger = logger;
}

public async Task<Dictionary<string, Dictionary<string, long>>> GetPackageDownloadsAsync()
Expand Down
3 changes: 1 addition & 2 deletions src/BaGetter.Core/Validation/RequiredIfAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ namespace BaGetter.Core;

/// <summary>
/// Provides conditional validation based on related property value.
///
/// Inspiration: https://stackoverflow.com/a/27666044
/// </summary>
/// <remarks>Inspiration: <see href="https://stackoverflow.com/a/27666044"/></remarks>
[AttributeUsage(AttributeTargets.Property)]
public sealed class RequiredIfAttribute : ValidationAttribute
{
Expand Down
2 changes: 1 addition & 1 deletion src/BaGetter.Web/OperationCancelledMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ namespace BaGetter.Web;

/// <summary>
/// Captures <see cref="OperationCanceledException" /> and converts to HTTP 409 response.
/// Based off: https://github.com/aspnet/AspNetCore/blob/28157e62597bf0e043bc7e937e44c5ec81946b83/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs
/// </summary>
/// <remarks>Based off: <see href="https://github.com/aspnet/AspNetCore/blob/28157e62597bf0e043bc7e937e44c5ec81946b83/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs"/></remarks>
public class OperationCancelledMiddleware
{
private readonly RequestDelegate _next;
Expand Down
Loading

0 comments on commit 0700615

Please sign in to comment.