Skip to content

Commit

Permalink
Merge pull request #23 from pyrocumulus/validation
Browse files Browse the repository at this point in the history
Add argument validation to all api methods
  • Loading branch information
pyrocumulus authored Mar 15, 2020
2 parents c950684 + 7f4bb94 commit 801d243
Show file tree
Hide file tree
Showing 28 changed files with 680 additions and 32 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Codecov

on:
push:
branches-ignore:
- gh-pages

jobs:
test_and_upload_coverage:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.100
- name: Test with dotnet
run: dotnet test --configuration Release /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
- name: Code coverage
uses: codecov/codecov-action@v1

3 changes: 2 additions & 1 deletion .github/workflows/dotnetcore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ jobs:
- name: Build with dotnet
run: dotnet build --configuration Release
- name: Test with dotnet
run: dotnet test --configuration Release
run: dotnet test

18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,24 @@
[![NuGet Downloads](https://img.shields.io/nuget/dt/PVOutput.Net.svg?logo=nuget)](https://www.nuget.org/packages/PVOutput.Net/)
[![fuget](https://www.fuget.org/packages/PVOutput.Net/badge.svg)](https://www.fuget.org/packages/PVOutput.Net)
![.NET Core](https://img.shields.io/github/workflow/status/pyrocumulus/PVOutput.Net/.NET%20Core/develop)
![Code coverage](https://img.shields.io/codecov/c/github/pyrocumulus/PVOutput.Net/develop)

## Installation

Installation can be done through installation of the [NuGet package](https://www.nuget.org/packages/PVOutput.Net/).
Installation can be done through installation of the [NuGet package](https://www.nuget.org/packages/PVOutput.Net/):

## Usage
```posh
PM> Install-Package PVOutput.Net
```

## Support

This library is targeting .NET Standard 2.0 and above. For full compatibility details, check the [Microsoft Docs](https://docs.microsoft.com/nl-nl/dotnet/standard/net-standard#net-implementation-support).

**Please note:** that the default branch of the repository is `develop`. This means that it can contain bugfixes/features that are not yet available in the NuGet package.
See [master](https://github.com/pyrocumulus/pvoutput.net/tree/master) for the source code, that was used for building the NuGet package.

## Basic usage

### Getting data out of PVOutput.org

Expand Down Expand Up @@ -60,7 +72,7 @@ For more information on usage, please see the [documentation](https://pyrocumulu

## API Coverage

The library covers almost nearly all the official PVOutput API exposes. See [documentation](https://pyrocumulus.github.io/pvoutput.net/) for details.
The library covers almost all of the methods the official PVOutput API exposes. See [documentation](https://pyrocumulus.github.io/pvoutput.net/) for details.

## Building the project

Expand Down
10 changes: 9 additions & 1 deletion docfx/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@
## Installation

Installation can be done through installation of the [NuGet package](https://www.nuget.org/packages/PVOutput.Net/).
Installation can be done through installation of the [NuGet package](https://www.nuget.org/packages/PVOutput.Net/):

```posh
PM> Install-Package PVOutput.Net
```

## Support

This library is targeting .NET Standard 2.0 and above. For full compatibility details, check the [Microsoft Docs](https://docs.microsoft.com/nl-nl/dotnet/standard/net-standard#net-implementation-support).

## Usage

Expand Down
4 changes: 4 additions & 0 deletions src/PVOutput.Net/Modules/ExtendedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Dawn;
using PVOutput.Net.Objects;
using PVOutput.Net.Requests.Handler;
using PVOutput.Net.Requests.Modules;
Expand Down Expand Up @@ -44,6 +45,9 @@ public Task<PVOutputResponse<IExtended>> GetRecentExtendedDataAsync(Cancellation
/// <returns>List of extended data objects.</returns>
public Task<PVOutputArrayResponse<IExtended>> GetExtendedDataForPeriodAsync(DateTime fromDate, DateTime toDate, int? limit = null, CancellationToken cancellationToken = default)
{
Guard.Argument(toDate, nameof(toDate)).GreaterThan(fromDate);
Guard.Argument(limit, nameof(limit)).LessThan(50);

var handler = new RequestHandler(Client);
return handler.ExecuteArrayRequestAsync<IExtended>(new ExtendedRequest() { FromDate = fromDate, ToDate = toDate, Limit = limit }, cancellationToken);
}
Expand Down
3 changes: 3 additions & 0 deletions src/PVOutput.Net/Modules/MissingService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Dawn;
using PVOutput.Net.Objects;
using PVOutput.Net.Requests.Handler;
using PVOutput.Net.Requests.Modules;
Expand Down Expand Up @@ -28,6 +29,8 @@ internal MissingService(PVOutputClient client) : base(client)
/// <returns>List of missing dates</returns>
public Task<PVOutputResponse<IMissing>> GetMissingDaysInPeriodAsync(DateTime fromDate, DateTime toDate, CancellationToken cancellationToken = default)
{
Guard.Argument(toDate, nameof(toDate)).GreaterThan(fromDate);

var handler = new RequestHandler(Client);
return handler.ExecuteSingleItemRequestAsync<IMissing>(new MissingRequest { FromDate = fromDate, ToDate = toDate }, cancellationToken);
}
Expand Down
25 changes: 19 additions & 6 deletions src/PVOutput.Net/Modules/OutputService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Dawn;
using PVOutput.Net.Enums;
using PVOutput.Net.Objects;
using PVOutput.Net.Objects.Core;
using PVOutput.Net.Requests.Handler;
using PVOutput.Net.Requests.Modules;
using PVOutput.Net.Responses;
Expand All @@ -30,8 +32,9 @@ internal OutputService(PVOutputClient client) : base(client)
/// <returns>Output for the requested date.</returns>
public Task<PVOutputResponse<IOutput>> GetOutputForDateAsync(DateTime date, bool getInsolation = false, int? systemId = null, CancellationToken cancellationToken = default)
{
var handler = new RequestHandler(Client);
Guard.Argument(date, nameof(date)).Max(DateTime.Today);

var handler = new RequestHandler(Client);
return handler.ExecuteSingleItemRequestAsync<IOutput>(new OutputRequest { FromDate = date, ToDate = date, SystemId = systemId, Insolation = getInsolation }, cancellationToken);
}

Expand All @@ -46,8 +49,10 @@ public Task<PVOutputResponse<IOutput>> GetOutputForDateAsync(DateTime date, bool
/// <returns>Outputs for the requested period.</returns>
public Task<PVOutputArrayResponse<IOutput>> GetOutputsForPeriodAsync(DateTime fromDate, DateTime toDate, bool getInsolation = false, int? systemId = null, CancellationToken cancellationToken = default)
{
var handler = new RequestHandler(Client);
Guard.Argument(toDate, nameof(toDate)).GreaterThan(fromDate).IsNoFutureDate().NoTimeComponent();
Guard.Argument(fromDate, nameof(fromDate)).NoTimeComponent();

var handler = new RequestHandler(Client);
return handler.ExecuteArrayRequestAsync<IOutput>(new OutputRequest { FromDate = fromDate, ToDate = toDate, SystemId = systemId, Insolation = getInsolation }, cancellationToken);
}

Expand All @@ -60,8 +65,9 @@ public Task<PVOutputArrayResponse<IOutput>> GetOutputsForPeriodAsync(DateTime fr
/// <returns>Team output for the requested date.</returns>
public Task<PVOutputResponse<ITeamOutput>> GetTeamOutputForDateAsync(DateTime date, int teamId, CancellationToken cancellationToken = default)
{
var handler = new RequestHandler(Client);
Guard.Argument(date, nameof(date)).Max(DateTime.Today);

var handler = new RequestHandler(Client);
return handler.ExecuteSingleItemRequestAsync<ITeamOutput>(new OutputRequest { FromDate = date, ToDate = date, TeamId = teamId }, cancellationToken);
}

Expand All @@ -75,8 +81,10 @@ public Task<PVOutputResponse<ITeamOutput>> GetTeamOutputForDateAsync(DateTime da
/// <returns>Team outputs Outputs for the requested period.</returns>
public Task<PVOutputArrayResponse<ITeamOutput>> GetTeamOutputsForPeriodAsync(DateTime fromDate, DateTime toDate, int teamId, CancellationToken cancellationToken = default)
{
var handler = new RequestHandler(Client);
Guard.Argument(toDate, nameof(toDate)).GreaterThan(fromDate).IsNoFutureDate().NoTimeComponent();
Guard.Argument(fromDate, nameof(fromDate)).NoTimeComponent();

var handler = new RequestHandler(Client);
return handler.ExecuteArrayRequestAsync<ITeamOutput>(new OutputRequest { FromDate = fromDate, ToDate = toDate, TeamId = teamId }, cancellationToken);
}

Expand All @@ -90,8 +98,10 @@ public Task<PVOutputArrayResponse<ITeamOutput>> GetTeamOutputsForPeriodAsync(Dat
/// <returns>Aggregated outputs for the requested period.</returns>
public Task<PVOutputArrayResponse<IAggregatedOutput>> GetAggregatedOutputsAsync(DateTime fromDate, DateTime toDate, AggregationPeriod period, CancellationToken cancellationToken = default)
{
var handler = new RequestHandler(Client);
Guard.Argument(toDate, nameof(toDate)).GreaterThan(fromDate).IsNoFutureDate().NoTimeComponent();
Guard.Argument(fromDate, nameof(fromDate)).NoTimeComponent();

var handler = new RequestHandler(Client);
return handler.ExecuteArrayRequestAsync<IAggregatedOutput>(new OutputRequest { FromDate = fromDate, ToDate = toDate, Aggregation = period }, cancellationToken);
}

Expand All @@ -104,6 +114,8 @@ public Task<PVOutputArrayResponse<IAggregatedOutput>> GetAggregatedOutputsAsync(
/// <returns>If the operation succeeded.</returns>
public Task<PVOutputBasicResponse> AddOutputAsync(IOutputPost output, CancellationToken cancellationToken = default)
{
Guard.Argument(output, nameof(output)).NotNull();

var handler = new RequestHandler(Client);
return handler.ExecutePostRequestAsync(new AddOutputRequest() { Output = output }, cancellationToken);
}
Expand All @@ -117,9 +129,10 @@ public Task<PVOutputBasicResponse> AddOutputAsync(IOutputPost output, Cancellati
/// <returns>If the operation succeeded.</returns>
public Task<PVOutputBasicResponse> AddBatchOutputAsync(IEnumerable<IBatchOutputPost> outputs, CancellationToken cancellationToken = default)
{
Guard.Argument(outputs, nameof(outputs)).NotNull().NotEmpty();

var handler = new RequestHandler(Client);
return handler.ExecutePostRequestAsync(new AddBatchOutputRequest() { Outputs = outputs }, cancellationToken);
}

}
}
4 changes: 3 additions & 1 deletion src/PVOutput.Net/Modules/SearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Dawn;
using PVOutput.Net.Objects;
using PVOutput.Net.Requests.Handler;
using PVOutput.Net.Requests.Modules;
Expand Down Expand Up @@ -31,8 +32,9 @@ internal SearchService(PVOutputClient client) : base(client)
/// <returns>A list of search results.</returns>
public Task<PVOutputArrayResponse<ISystemSearchResult>> SearchAsync(string searchQuery, PVCoordinate? coordinate = null, CancellationToken cancellationToken = default)
{
var handler = new RequestHandler(Client);
Guard.Argument(searchQuery, nameof(searchQuery)).NotEmpty().NotNull();

var handler = new RequestHandler(Client);
return handler.ExecuteArrayRequestAsync<ISystemSearchResult>(new SearchRequest { SearchQuery = searchQuery, Coordinate = coordinate }, cancellationToken);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/PVOutput.Net/Modules/StatisticsService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Dawn;
using PVOutput.Net.Objects;
using PVOutput.Net.Requests.Handler;
using PVOutput.Net.Requests.Modules;
Expand Down Expand Up @@ -46,6 +47,8 @@ public Task<PVOutputResponse<IStatistic>> GetLifetimeStatisticsAsync(bool includ
/// <returns>Statistical information for the requested period.</returns>
public Task<PVOutputResponse<IStatistic>> GetStatisticsForPeriodAsync(DateTime fromDate, DateTime toDate, bool includeConsumptionAndImport = false, bool includeCreditDebit = false, int? systemId = null, CancellationToken cancellationToken = default)
{
Guard.Argument(toDate, nameof(toDate)).GreaterThan(fromDate);

var handler = new RequestHandler(Client);
return handler.ExecuteSingleItemRequestAsync<IStatistic>(new StatisticPeriodRequest { FromDate = fromDate, ToDate = toDate, SystemId = systemId, IncludeConsumptionImport = includeConsumptionAndImport, IncludeCreditDebit = includeCreditDebit }, cancellationToken);
}
Expand Down
20 changes: 17 additions & 3 deletions src/PVOutput.Net/Modules/StatusService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Dawn;
using PVOutput.Net.Objects;
using PVOutput.Net.Objects.Core;
using PVOutput.Net.Requests.Handler;
using PVOutput.Net.Requests.Modules;
using PVOutput.Net.Responses;
Expand All @@ -20,14 +22,16 @@ internal StatusService(PVOutputClient client) : base(client)
}

/// <summary>
/// Get the system status a a specific moment.
/// Get the system status at a specific moment.
/// </summary>
/// <param name="moment">Moment to retrieve the system status for.</param>
/// <param name="systemId">Retrieve status for a specific system. <strong>Note: this is a donation only parameter.</strong></param>
/// <param name="cancellationToken">A cancellation token for the request.</param>
/// <returns>Status at the specified moment.</returns>
public Task<PVOutputResponse<IStatus>> GetStatusForDateTimeAsync(DateTime moment, int? systemId = null, CancellationToken cancellationToken = default)
{
Guard.Argument(moment, nameof(moment)).IsNoFutureDate();

var handler = new RequestHandler(Client);
return handler.ExecuteSingleItemRequestAsync<IStatus>(new GetStatusRequest { Date = moment, SystemId = systemId }, cancellationToken);
}
Expand All @@ -45,6 +49,8 @@ public Task<PVOutputResponse<IStatus>> GetStatusForDateTimeAsync(DateTime moment
/// <returns>Statusses for the specified period.</returns>
public Task<PVOutputArrayResponse<IStatusHistory>> GetHistoryForPeriodAsync(DateTime fromDateTime, DateTime toDateTime, bool ascending = false, int? systemId = null, bool extendedData = false, int? limit = null, CancellationToken cancellationToken = default)
{
Guard.Argument(toDateTime, nameof(toDateTime)).GreaterThan(fromDateTime).IsNoFutureDate();

var handler = new RequestHandler(Client);
return handler.ExecuteArrayRequestAsync<IStatusHistory>(
new GetStatusRequest { Date = fromDateTime.Date, From = fromDateTime, To = toDateTime, Ascending = ascending, SystemId = systemId, Extended = extendedData, Limit = limit, History = true }, cancellationToken);
Expand All @@ -56,10 +62,12 @@ public Task<PVOutputArrayResponse<IStatusHistory>> GetHistoryForPeriodAsync(Date
/// <param name="fromDateTime">Minimum datetime for the requested range.</param>
/// <param name="toDateTime">Maximum datetime for the requested range.</param>
/// <param name="systemId">Retrieve statuses for a specific system. <strong>Note: this is a donation only parameter.</strong></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <param name="cancellationToken">A cancellation token for the request.</param>
/// <returns>Day statistics for the specified period.</returns>
public Task<PVOutputResponse<IDayStatistics>> GetDayStatisticsForPeriodAsync(DateTime fromDateTime, DateTime toDateTime, int? systemId = null, CancellationToken cancellationToken = default)
{
Guard.Argument(toDateTime, nameof(toDateTime)).GreaterThan(fromDateTime).IsNoFutureDate();

var handler = new RequestHandler(Client);
var response = handler.ExecuteSingleItemRequestAsync<IDayStatistics>(new GetDayStatisticsRequest { Date = fromDateTime.Date, From = fromDateTime, To = toDateTime, SystemId = systemId }, cancellationToken);

Expand Down Expand Up @@ -88,6 +96,8 @@ private static PVOutputResponse<IDayStatistics> AddRequestedDate(Task<PVOutputRe
/// <returns>If the operation succeeded.</returns>
public Task<PVOutputBasicResponse> AddStatusAsync(IStatusPost status, CancellationToken cancellationToken = default)
{
Guard.Argument(status, nameof(status)).NotNull();

var handler = new RequestHandler(Client);
return handler.ExecutePostRequestAsync(new AddStatusRequest() { StatusPost = status }, cancellationToken);
}
Expand All @@ -101,6 +111,8 @@ public Task<PVOutputBasicResponse> AddStatusAsync(IStatusPost status, Cancellati
/// <returns>If the operation succeeded.</returns>
public Task<PVOutputArrayResponse<IBatchStatusPostResult>> AddBatchStatusAsync(IEnumerable<IBatchStatusPost> statuses, CancellationToken cancellationToken = default)
{
Guard.Argument(statuses, nameof(statuses)).NotNull().NotEmpty();

var handler = new RequestHandler(Client);
return handler.ExecuteArrayRequestAsync<IBatchStatusPostResult>(new AddBatchStatusRequest() { StatusPosts = statuses }, cancellationToken); ;
}
Expand All @@ -114,6 +126,8 @@ public Task<PVOutputArrayResponse<IBatchStatusPostResult>> AddBatchStatusAsync(I
/// <returns>If the operation succeeded.</returns>
public Task<PVOutputBasicResponse> DeleteStatusAsync(DateTime moment, CancellationToken cancellationToken = default)
{
Guard.Argument(moment, nameof(moment)).IsNoFutureDate();

var handler = new RequestHandler(Client);
return handler.ExecutePostRequestAsync(new DeleteStatusRequest() { Timestamp = moment }, cancellationToken);
}
Expand Down
4 changes: 1 addition & 3 deletions src/PVOutput.Net/Modules/SupplyService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ internal SupplyService(PVOutputClient client) : base(client)
public Task<PVOutputArrayResponse<ISupply>> GetSupplyAsync(string timeZone = null, string regionKey = null, CancellationToken cancellationToken = default)
{
var handler = new RequestHandler(Client);

return handler.ExecuteArrayRequestAsync<ISupply>(
new SupplyRequest { TimeZone = timeZone, RegionKey = regionKey }, cancellationToken);
return handler.ExecuteArrayRequestAsync<ISupply>(new SupplyRequest { TimeZone = timeZone, RegionKey = regionKey }, cancellationToken);
}
}
}
2 changes: 0 additions & 2 deletions src/PVOutput.Net/Modules/SystemService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ internal SystemService(PVOutputClient client) : base(client)
public Task<PVOutputResponse<ISystem>> GetOwnSystemAsync(CancellationToken cancellationToken = default)
{
var handler = new RequestHandler(Client);

return handler.ExecuteSingleItemRequestAsync<ISystem>(new SystemRequest(), cancellationToken);
}

Expand All @@ -39,7 +38,6 @@ public Task<PVOutputResponse<ISystem>> GetOwnSystemAsync(CancellationToken cance
public Task<PVOutputResponse<ISystem>> GetOtherSystemAsync(int systemId, CancellationToken cancellationToken = default)
{
var handler = new RequestHandler(Client);

return handler.ExecuteSingleItemRequestAsync<ISystem>(new SystemRequest { SystemId = systemId, MonthlyEstimates = false }, cancellationToken);
}
}
Expand Down
28 changes: 28 additions & 0 deletions src/PVOutput.Net/Objects/Core/GuardExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
using Dawn;

namespace PVOutput.Net.Objects.Core
{
internal static class GuardExtensions
{
internal static Guard.ArgumentInfo<DateTime> IsNoFutureDate(this Guard.ArgumentInfo<DateTime> argument)
{
return argument.LessThan(DateTime.Today.AddDays(1));
}

public static ref readonly Guard.ArgumentInfo<DateTime> NoTimeComponent(in this Guard.ArgumentInfo<DateTime> argument)
{
if (argument.Value.TimeOfDay != TimeSpan.Zero)
{
throw Guard.Fail(new ArgumentException(
$"{argument.Name} has a time component." +
"Please only use DateTime.Date instead.",
argument.Name));
}

return ref argument;
}
}
}
2 changes: 1 addition & 1 deletion src/PVOutput.Net/Objects/ExtendedDataConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace PVOutput.Net.Objects
/// <summary>
/// Element describing a configured extended data value
/// </summary>
public struct ExtendedDataConfiguration : IEquatable<ExtendedDataConfiguration>
public readonly struct ExtendedDataConfiguration : IEquatable<ExtendedDataConfiguration>
{
/// <summary>The label that the extended value has</summary>
public string Label { get; }
Expand Down
Loading

0 comments on commit 801d243

Please sign in to comment.