Skip to content
This repository has been archived by the owner on May 6, 2024. It is now read-only.

FUNCTIONS: Get All Authors #8

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3ee9123
CODE RUB: Clean up
Nov 18, 2023
b2fd4b1
CODE RUB: Clean up
Nov 18, 2023
0629df0
INFRA: Initialize Project
Nov 18, 2023
52d0c7e
INFRA: Initialize Unit Tests Project
Nov 18, 2023
32ea601
INFRA: Initialize Authors Project
Nov 18, 2023
75e93a1
FOUNDATIONS: Get All Authors
Nov 18, 2023
5110b56
FUNCTIONS: Load Feed
Nov 18, 2023
2903e3a
BROKERS: Read Feed
Nov 18, 2023
0dd64c5
BROKERS: GetAllAuthors
Nov 19, 2023
9ba3c06
BROKERS: SerializeFeed
Nov 19, 2023
9123a4a
FUNCTIONS: Load Feeds
Nov 19, 2023
db036a5
FOUNDATIONS: Combined Feed
Nov 28, 2023
43f73e1
BROKERS: Serialize Feed
Nov 29, 2023
5e105f8
FOUNDATIONS: Load Feed
Nov 29, 2023
5ff7082
PROCESSINGS: Process Feed Loading
Nov 29, 2023
75e1921
FUNCTIONS: Load Feeds Function
Nov 29, 2023
802283f
CODE RUB: Clean up
Nov 29, 2023
ad0f059
CODE RUB: Clean up
Nov 29, 2023
7e7969c
CODE RUB: Clean up
Nov 29, 2023
45f71a8
FOUNDATIONS: Retrieve All Authors
Nov 29, 2023
0a1efa3
ShouldRetrieveAllAuthorsAsync -> PASS
Nov 29, 2023
32748a5
ShouldThrowCriticalDependencyExceptionOnRetrieveAllWhenAssemblyExcept…
Nov 29, 2023
1c8461f
ShouldThrowCriticalDependencyExceptionOnRetrieveAllWhenAssemblyExcept…
Nov 29, 2023
ce6a1c9
ShouldThrowCriticalDependencyExceptionOnRetrieveAllIfDependencyErrorO…
Nov 29, 2023
049ca5c
ShouldThrowCriticalDependencyExceptionOnRetrieveAllIfDependencyErrorO…
Nov 29, 2023
15cb28c
ShouldThrowServiceExceptionOnRetrieveAllIfServiceErrorOccursAndLogItA…
Nov 29, 2023
88c7939
ShouldThrowServiceExceptionOnRetrieveAllIfServiceErrorOccursAndLogItA…
Nov 29, 2023
fb31653
FUNCTIONS: Get All Authors
Nov 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# To learn more about .editorconfig see https://aka.ms/editorconfigdocs

# C# or VB files
[*.{cs,vb}]
guidelines = 120

#### Core EditorConfig Options ####

#Formatting - header template
file_header_template = ---------------------------------------------------------------\nCopyright (c) 2023 Planet Dotnet. All rights reserved.\nLicensed under the MIT License.\nSee License.txt in the project root for license information.\n---------------------------------------------------------------

# Indentation and spacing
indent_size = 4
indent_style = space
tab_width = 4

# New line preferences
end_of_line = crlf
insert_final_newline = false

#### .NET Coding Conventions ####

# Organize usings
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false

19 changes: 19 additions & 0 deletions Authors/mabroukmahdhi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"firstName": "Mabrouk",
"lastName": "Mahdhi",
"stateOrRegion": "Darmstadt, Germany",
"emailAddress": "contact@mahdhi.com",
"tagOrBio": "is a Senior Technical Consultant who blogs, talks and develops all around mobile and web development.",
"webSite": "https://mahdhi.com",
"twitterHandle": "mabrouk_mahdhi",
"githubHandle": "mabroukmahdhi",
"gravatarHash": "1f5b179abb9b9f8a34a4a9799e205c96",
"feedUris": [
"https://medium.com/feed/@mabroukmahdhi"
],
"position": {
"lat": 49.873207,
"lon": 8.650779
},
"languageCode": "en"
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
using Newtonsoft.Json;
// ---------------------------------------------------------------
// Copyright (c) 2023 Planet Dotnet. All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using PlanetDotnet.Authors.Models.GeoPositions;

namespace PlanetDotnetAuthors.Models
namespace PlanetDotnet.Authors.Models.Authors
{
public class Author
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// ---------------------------------------------------------------
// Copyright (c) 2023 Planet Dotnet. All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------

using System;

namespace PlanetDotnet.Authors.Models.Authors.Exceptions
{
public class AuthorDependencyException : Exception
{
public AuthorDependencyException(Exception innerException) :
base(message: "Author dependency error occurred, contact support.", innerException)
{ }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// ---------------------------------------------------------------
// Copyright (c) 2023 Planet Dotnet. All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------

using System;

namespace PlanetDotnet.Authors.Models.Authors.Exceptions
{
public class AuthorServiceException : Exception
{
public AuthorServiceException(Exception innerException)
: base(message: "Author service error occurred, contact support.", innerException) { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// ---------------------------------------------------------------
// Copyright (c) 2023 Planet Dotnet. All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------

using System;

namespace PlanetDotnet.Authors.Models.Authors.Exceptions
{
public class FailedAuthorStorageException : Exception
{
public FailedAuthorStorageException(Exception innerException)
: base("Failed authors storage error occurred, contact support.", innerException)
{ }
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
using Newtonsoft.Json;
// ---------------------------------------------------------------
// Copyright (c) 2023 Planet Dotnet. All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------

namespace PlanetDotnetAuthors.Models
using Newtonsoft.Json;

namespace PlanetDotnet.Authors.Models.GeoPositions
{
public class GeoPosition
{
Expand Down
17 changes: 17 additions & 0 deletions PlanetDotnet.Authors/PlanetDotnet.Authors.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="..\Authors\*.json" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
using Newtonsoft.Json;
using PlanetDotnetAuthors.Models;
// ---------------------------------------------------------------
// Copyright (c) 2023 Planet Dotnet. All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Newtonsoft.Json;
using PlanetDotnet.Authors.Models.Authors;

namespace PlanetDotnetAuthors
namespace PlanetDotnet.Authors.Services
{
public static class AuthorsLoader
public static class AuthorService
{
public static async Task<IEnumerable<Author>> GetAllAuthors()
{
var assembly = Assembly.GetExecutingAssembly();
var resourceNames = assembly.GetManifestResourceNames();
var authorsResourceNames = resourceNames.Where(res =>
res.StartsWith("PlanetDotnetAuthors", StringComparison.OrdinalIgnoreCase) &&
res.StartsWith("PlanetDotnet.Authors", StringComparison.OrdinalIgnoreCase) &&
res.EndsWith(".json", StringComparison.OrdinalIgnoreCase));

var authorsTasks = authorsResourceNames.Select(name => ReadAuthor(assembly, name));
Expand Down
16 changes: 16 additions & 0 deletions PlanetDotnet.Tests.Unit/DeleteMe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// ---------------------------------------------------------------
// Copyright (c) 2023 Planet Dotnet. All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------

using Xunit;

namespace PlanetDotnet.Tests.Unit
{
public class DeleteMe
{
[Fact]
public void ShouldBeTrue() => Assert.True(true);
}
}
32 changes: 32 additions & 0 deletions PlanetDotnet.Tests.Unit/PlanetDotnet.Tests.Unit.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CleanMoq" Version="1.0.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1" />
<PackageReference Include="Tynamix.ObjectFiller" Version="1.5.8" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\PlanetDotnet\PlanetDotnet.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// ---------------------------------------------------------------
// Copyright (c) 2023 Planet Dotnet. All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------

using System;
using System.Threading.Tasks;
using Moq;
using PlanetDotnet.Authors.Models.Authors.Exceptions;
using Xunit;

namespace PlanetDotnet.Tests.Unit.Services.Foundations.Authors
{
public partial class AuthorServiceTests
{

[Theory]
[MemberData(nameof(DependencyExceptions))]
public async Task ShouldThrowCriticalDependencyExceptionOnRetrieveAllIfDependencyErrorOccursAndLogIt(
Exception dependencyException)
{
// given
var failedStorageException =
new FailedAuthorStorageException(dependencyException);

var expectedAuthorDependencyException =
new AuthorDependencyException(failedStorageException);

this.authorBrokerMock.Setup(broker =>
broker.GetAllAuthorsAsync())
.Throws(dependencyException);

// when
var retrieveAllAuthorsTask =
this.authorService.RetrieveAllAuthorsAsync();

// then
await Assert.ThrowsAsync<AuthorDependencyException>(() =>
retrieveAllAuthorsTask.AsTask());

this.authorBrokerMock.Verify(broker =>
broker.GetAllAuthorsAsync(),
Times.Once);

this.loggingBrokerMock.Verify(broker =>
broker.LogCritical(It.Is(SameExceptionAs(
expectedAuthorDependencyException))),
Times.Once);

this.authorBrokerMock.VerifyNoOtherCalls();
this.loggingBrokerMock.VerifyNoOtherCalls();
}

[Fact]
public async Task ShouldThrowServiceExceptionOnRetrieveAllIfServiceErrorOccursAndLogItAsync()
{
// given
var serviceException = new Exception();

var expectedAuthorServiceException =
new AuthorServiceException(serviceException);

this.authorBrokerMock.Setup(broker =>
broker.GetAllAuthorsAsync())
.ThrowsAsync(serviceException);

// when
var retrievedAuthorTask =
this.authorService.RetrieveAllAuthorsAsync();

// then
await Assert.ThrowsAsync<AuthorServiceException>(() =>
retrievedAuthorTask.AsTask());

this.authorBrokerMock.Verify(broker =>
broker.GetAllAuthorsAsync(),
Times.Once);

this.loggingBrokerMock.Verify(broker =>
broker.LogError(It.Is(SameExceptionAs(
expectedAuthorServiceException))),
Times.Once);

this.authorBrokerMock.VerifyNoOtherCalls();
this.loggingBrokerMock.VerifyNoOtherCalls();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// ---------------------------------------------------------------
// Copyright (c) 2023 Planet Dotnet. All rights reserved.
// Licensed under the MIT License.
// See License.txt in the project root for license information.
// ---------------------------------------------------------------

using System.Collections.Generic;
using System.Threading.Tasks;
using FluentAssertions;
using Moq;
using PlanetDotnet.Authors.Models.Authors;
using Xunit;

namespace PlanetDotnet.Tests.Unit.Services.Foundations.Authors
{
public partial class AuthorServiceTests
{
[Fact]
public async Task ShouldRetrieveAllAuthorsAsync()
{
// given
IEnumerable<Author> randomAuthors = CreateRandomAuthors();
IEnumerable<Author> storageAuthors = randomAuthors;
IEnumerable<Author> expectedAuthors = storageAuthors;

this.authorBrokerMock.Setup(broker =>
broker.GetAllAuthorsAsync())
.ReturnsAsync(expectedAuthors);

// when
var actualAuthors =
await this.authorService.RetrieveAllAuthorsAsync();

// then
actualAuthors.Should().BeEquivalentTo(expectedAuthors);

this.authorBrokerMock.Verify(broker =>
broker.GetAllAuthorsAsync(),
Times.Once());

this.authorBrokerMock.VerifyNoOtherCalls();
}
}
}
Loading