Skip to content

Commit

Permalink
Adding validation and simple logging
Browse files Browse the repository at this point in the history
  • Loading branch information
Iestyn Jones committed May 10, 2023
1 parent cf12697 commit e1d0126
Show file tree
Hide file tree
Showing 17 changed files with 374 additions and 54 deletions.
2 changes: 1 addition & 1 deletion src/ProjectPatterns/Patterns/LoggingPattern.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project>

<ItemGroup>
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FizzBuzzRequestValidatorTests.cs" company="Bugail Consulting Ltd">
// Copyright 2023 (c) Bugail Consulting Ltd. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace UL.Core.Tests.Validators
{
using Bogus;
using FluentValidation.TestHelper;
using NUnit.Framework;
using UL.Core.Requests;
using UL.Core.Validators;

public class FizzBuzzRequestValidatorTests
{
private FizzBuzzRequestValidator validator;

[SetUp]
public void Setup()
{
validator = new FizzBuzzRequestValidator();
}

[TestCase("")]
[TestCase(null)]
[TestCase("12x")]
public void Validate_InvalidStart_HasErrors(string value)
{
// Arrange
var model = new FizzBuzzRequest(value, string.Empty);

// Act
var result = validator.TestValidate(model);

// Assert
result.ShouldHaveValidationErrorFor(person => person.Start);
}

[TestCase("")]
[TestCase(null)]
[TestCase("12x")]
[TestCase("0")]
public void Validate_InvalidEnd_HasErrors(string value)
{
// Arrange
var model = new FizzBuzzRequest(string.Empty, value);

// Act
var result = validator.TestValidate(model);

// Assert
result.ShouldHaveValidationErrorFor(person => person.End);
}
}
}
20 changes: 19 additions & 1 deletion src/Tests/UL.Services.Tests/FizzBuzzServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,27 @@ namespace UL.Services.Tests
using NSubstitute;
using NUnit.Framework;
using UL.Abstractions.Interfaces;
using UL.Core.Requests;
using Ul.Services.Strategies;

[TestFixture]
public class FizzBuzzServiceTests
{
private List<IFizzBuzzStrategy> stategies;
private FizzBuzzService target;
private ILogger<FizzBuzzService> logger;

[SetUp]
public void Setup()
{
this.logger = Substitute.For<ILogger<FizzBuzzService>>();
this.stategies = new List<IFizzBuzzStrategy>
{
new FizzStrategy(),
new BuzzStrategy()
};

this.target = new FizzBuzzService(this.stategies);
this.target = new FizzBuzzService(this.stategies, this.logger);
}

[Test]
Expand Down Expand Up @@ -76,5 +79,20 @@ public void GetFizzBuzzList_EmptyCollection_ThrowsException()
.Throw<ArgumentException>()
.WithMessage("*collection*");
}

[Test]
public void GetFizzBuzzList_NullRequest_ThrowsException()
{
// Arrange
FizzBuzzRequest request = null;

// Act
Func<IEnumerable<string>> action = () => this.target.GetFizzBuzzList(request);

// Assert
action.Should()
.Throw<ArgumentNullException>()
.WithMessage("*request*");
}
}
}
10 changes: 9 additions & 1 deletion src/UL.Abstractions/Interfaces/IFizzBuzzService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
namespace UL.Abstractions.Interfaces
{
using System.Collections.Generic;
using UL.Core.Requests;

/// <summary>
/// The fizz buzz service interface.
Expand All @@ -18,6 +19,13 @@ public interface IFizzBuzzService
/// </summary>
/// <param name="collection">The collection</param>
/// <returns>A list of <see cref="string"/>.</returns>
IList<string> GetFizzBuzzList(IEnumerable<int> collection);
IEnumerable<string> GetFizzBuzzList(IEnumerable<int> collection);

/// <summary>
/// Gets the list of FizzBuzz values.
/// </summary>
/// <param name="request">The request object.</param>
/// <returns>A list of <see cref="string"/>.</returns>
IEnumerable<string> GetFizzBuzzList(FizzBuzzRequest request);
}
}
4 changes: 4 additions & 0 deletions src/UL.Abstractions/UL.Abstractions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@

<Import Project="$(SolutionDir)/ProjectPatterns/Archetypes/SharedLibraryArchetype.props" />

<ItemGroup>
<ProjectReference Include="..\UL.Core\UL.Core.csproj" />
</ItemGroup>

</Project>
35 changes: 35 additions & 0 deletions src/UL.Core/Requests/FizzBuzzRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FizzBuzzRequest.cs" company="Bugail Consulting Ltd">
// Copyright 2023 (c) Bugail Consulting Ltd. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace UL.Core.Requests
{
/// <summary>
/// The fizzbuzz request.
/// </summary>
public class FizzBuzzRequest
{
/// <summary>
/// Initializes a new instance of the <see cref="FizzBuzzRequest"/> class.
/// </summary>
/// <param name="start">The start value.</param>
/// <param name="end">The end value.</param>
public FizzBuzzRequest(string start, string end)
{
this.Start = start;
this.End = end;
}

/// <summary>
/// Gets the start value.
/// </summary>
public string Start { get; }

/// <summary>
/// Gets the end value.
/// </summary>
public string End { get; }
}
}
4 changes: 4 additions & 0 deletions src/UL.Core/UL.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@

<Import Project="$(SolutionDir)/ProjectPatterns/Archetypes/SharedLibraryArchetype.props" />

<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.5.2" />
</ItemGroup>

</Project>
41 changes: 41 additions & 0 deletions src/UL.Core/Validators/FizzBuzzRequestValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FizzBuzzRequestValidator.cs" company="Bugail Consulting Ltd">
// Copyright 2023 (c) Bugail Consulting Ltd. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace UL.Core.Validators
{
using FluentValidation;
using UL.Core.Extensions;
using UL.Core.Requests;

/// <summary>
/// The fizz buzz validator.
/// </summary>
public class FizzBuzzRequestValidator : AbstractValidator<FizzBuzzRequest>
{
/// <summary>
/// Initializes a new instance of the <see cref="FizzBuzzRequestValidator"/> class.
/// </summary>
public FizzBuzzRequestValidator()
{
this.RuleFor(x => x.Start)
.NotEmpty()
.NotNull()
.Must(x => x.IsNumeric()).WithMessage("Start must be a valid number");

this.RuleFor(x => x.End)
.NotEmpty()
.NotNull()
.Must(x => x.IsNumeric()).WithMessage("End must be a valid number")
.Custom((x, context) =>
{
if (!int.TryParse(x, out int value) || value <= 0)
{
context.AddFailure($"End must be greater than 0.");
}
});
}
}
}
81 changes: 60 additions & 21 deletions src/UL.UI.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,54 @@

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using UL.Abstractions.Interfaces;
using UL.Core.Extensions;
using UL.Core.Requests;
using UL.Services.Extensions;

internal class Program
{
static void Main(string[] args)
{
using IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddServices();
})
.Build();
// Setup serilog static logger
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateBootstrapLogger();

var showMenu = true;
try
{
Log.Information("Starting Account Service Web");

using IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddServices();
})
.Build();

var showMenu = true;

while (showMenu)
while (showMenu)
{
showMenu = MainMenu(host.Services);
}
}
catch (Exception ex)
{
showMenu = MainMenu(host.Services);
Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
}

private static bool MainMenu(IServiceProvider provider)
private static bool MainMenu(IServiceProvider hostProvider)
{
using var serviceScope = hostProvider.CreateScope();
var provider = serviceScope.ServiceProvider;

Console.Clear();
Console.WriteLine("Choose an option:");
Console.WriteLine("1) FizzBuzz");
Expand All @@ -49,30 +72,45 @@ private static bool MainMenu(IServiceProvider provider)
}
}

private static void HandleFizzBuzz(IServiceProvider hostProvider)
private static void HandleFizzBuzz(IServiceProvider provider)
{
using var serviceScope = hostProvider.CreateScope();
var provider = serviceScope.ServiceProvider;
var service = provider.GetRequiredService<IFizzBuzzService>();
try
{
var service = provider.GetRequiredService<IFizzBuzzService>();

Console.Write("\n\n");
Console.Write("Calculate fizzbuzz for a range:\n");
Console.Write("--------------------------------------------");
Console.Write("\n\n");

Console.Write("Input the start : ");
var startValue = Console.ReadLine();

var list = Enumerable.Range(1, 100).ToList();
var result = service.GetFizzBuzzList(list);
Console.Write("Input the end : ");
var endString = Console.ReadLine();

foreach (var item in result)
var request = new FizzBuzzRequest(startValue, endString);
var result = service.GetFizzBuzzList(request);

foreach (var item in result)
{
Console.WriteLine(item);
}
}
catch (Exception e)
{
Console.WriteLine(item);
Console.WriteLine(e.Message);
}

Console.Write("\n\n");
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}

private static void HandleFactorial(IServiceProvider hostProvider)
private static void HandleFactorial(IServiceProvider provider)
{
try
{
using var serviceScope = hostProvider.CreateScope();
var provider = serviceScope.ServiceProvider;
var service = provider.GetRequiredService<IFactorialService>();

Console.Write("\n\n");
Expand All @@ -98,6 +136,7 @@ private static void HandleFactorial(IServiceProvider hostProvider)
Console.WriteLine(e.Message);
}

Console.Write("\n\n");
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();

Expand Down
3 changes: 3 additions & 0 deletions src/UL.UI.Console/UL.UI.Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<Import Project="$(SolutionDir)/ProjectPatterns/Patterns/LoggingPattern.props" />

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit e1d0126

Please sign in to comment.