diff --git a/ADotNet/ADotNet.csproj b/ADotNet/ADotNet.csproj index 10d168a..a3b1dc5 100644 --- a/ADotNet/ADotNet.csproj +++ b/ADotNet/ADotNet.csproj @@ -42,6 +42,7 @@ + diff --git a/ADotNet/Models/Pipelines/Releases/GithubPipelines/Exceptions/NullReleasePathException.cs b/ADotNet/Models/Pipelines/Releases/GithubPipelines/Exceptions/NullReleasePathException.cs new file mode 100644 index 0000000..f3e359c --- /dev/null +++ b/ADotNet/Models/Pipelines/Releases/GithubPipelines/Exceptions/NullReleasePathException.cs @@ -0,0 +1,22 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib 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.Linq; +using System.Text; +using System.Threading.Tasks; +using Xeptions; + +namespace ADotNet.Models.Pipelines.Releases.GithubPipelines.Exceptions +{ + public class NullReleasePathException : Xeption + { + public NullReleasePathException() + : base(message: "Release path is null.") + { } + } +} diff --git a/ADotNet/Models/Pipelines/Releases/GithubPipelines/Exceptions/NullReleasePipelineException.cs b/ADotNet/Models/Pipelines/Releases/GithubPipelines/Exceptions/NullReleasePipelineException.cs new file mode 100644 index 0000000..dba76f3 --- /dev/null +++ b/ADotNet/Models/Pipelines/Releases/GithubPipelines/Exceptions/NullReleasePipelineException.cs @@ -0,0 +1,17 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +using Xeptions; + +namespace ADotNet.Models.Pipelines.Releases.GithubPipelines.Exceptions +{ + public class NullReleasePipelineException : Xeption + { + public NullReleasePipelineException() + : base(message: "Release pipeline is null.") + { } + } +} diff --git a/ADotNet/Models/Pipelines/Releases/GithubPipelines/Exceptions/ReleaseValidationException.cs b/ADotNet/Models/Pipelines/Releases/GithubPipelines/Exceptions/ReleaseValidationException.cs new file mode 100644 index 0000000..d5660de --- /dev/null +++ b/ADotNet/Models/Pipelines/Releases/GithubPipelines/Exceptions/ReleaseValidationException.cs @@ -0,0 +1,23 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib 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.Linq; +using System.Text; +using System.Threading.Tasks; +using Xeptions; + +namespace ADotNet.Models.Pipelines.Releases.GithubPipelines.Exceptions +{ + public class ReleaseValidationException : Xeption + { + public ReleaseValidationException(Xeption innerException) + : base(message: "Release validation error occurred, fix the errors and try again.", + innerException) + { } + } +} diff --git a/ADotNet/Models/Pipelines/Releases/GithubPipelines/GithubReleasePipeline.cs b/ADotNet/Models/Pipelines/Releases/GithubPipelines/GithubReleasePipeline.cs new file mode 100644 index 0000000..8d323b5 --- /dev/null +++ b/ADotNet/Models/Pipelines/Releases/GithubPipelines/GithubReleasePipeline.cs @@ -0,0 +1,12 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +namespace ADotNet.Models.Pipelines.Releases.GithubPipelines +{ + public class GithubReleasePipeline + { + } +} diff --git a/ADotNet/Services/Releases/IReleaseService.cs b/ADotNet/Services/Releases/IReleaseService.cs new file mode 100644 index 0000000..9c89411 --- /dev/null +++ b/ADotNet/Services/Releases/IReleaseService.cs @@ -0,0 +1,13 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +namespace ADotNet.Services.Releases +{ + public interface IReleaseService + { + void SerializeWriteToFile(string path, object releasePipeline); + } +} diff --git a/ADotNet/Services/Releases/ReleaseService.Exceptions.cs b/ADotNet/Services/Releases/ReleaseService.Exceptions.cs new file mode 100644 index 0000000..ea5c0d9 --- /dev/null +++ b/ADotNet/Services/Releases/ReleaseService.Exceptions.cs @@ -0,0 +1,31 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +using ADotNet.Models.Pipelines.Releases.GithubPipelines.Exceptions; + +namespace ADotNet.Services.Releases +{ + public partial class ReleaseService + { + private delegate void ReturningNothingFunction(); + + private void TryCatch(ReturningNothingFunction returningNothingFunction) + { + try + { + returningNothingFunction(); + } + catch (NullReleasePathException nullReleasePathException) + { + throw new ReleaseValidationException(nullReleasePathException); + } + catch (NullReleasePipelineException nullReleasePipelineException) + { + throw new ReleaseValidationException(nullReleasePipelineException); + } + } + } +} diff --git a/ADotNet/Services/Releases/ReleaseService.Validations.cs b/ADotNet/Services/Releases/ReleaseService.Validations.cs new file mode 100644 index 0000000..89d5fed --- /dev/null +++ b/ADotNet/Services/Releases/ReleaseService.Validations.cs @@ -0,0 +1,26 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +using ADotNet.Models.Pipelines.Releases.GithubPipelines; +using ADotNet.Models.Pipelines.Releases.GithubPipelines.Exceptions; + +namespace ADotNet.Services.Releases +{ + public partial class ReleaseService + { + private static void ValidateInputs(string path, object pipeline) + { + switch(path, pipeline) + { + case (null, _): + throw new NullReleasePathException(); + + case (_, null): + throw new NullReleasePipelineException(); + } + } + } +} diff --git a/ADotNet/Services/Releases/ReleaseService.cs b/ADotNet/Services/Releases/ReleaseService.cs new file mode 100644 index 0000000..a4ebd9a --- /dev/null +++ b/ADotNet/Services/Releases/ReleaseService.cs @@ -0,0 +1,39 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +using System; +using ADotNet.Brokers.IOs; +using ADotNet.Brokers.Serializers; + +namespace ADotNet.Services.Releases +{ + public partial class ReleaseService : IReleaseService + { + private readonly IYamlBroker yamlBroker; + private readonly IFilesBroker filesBroker; + + public ReleaseService( + IYamlBroker yamlBroker, + IFilesBroker filesBroker) + { + this.yamlBroker = yamlBroker; + this.filesBroker = filesBroker; + } + + public void SerializeWriteToFile(string path, object releasePipeline) => + TryCatch(() => + { + ValidateInputs(path, releasePipeline); + + string serializedPipeline = + this.yamlBroker.SerializeToYaml(releasePipeline); + + this.filesBroker.WriteToFile( + path, + data: serializedPipeline); + }); + } +} diff --git a/AdoNet.Tests.Unit/AdoNet.Tests.Unit.csproj b/AdoNet.Tests.Unit/AdoNet.Tests.Unit.csproj index e6c1bd6..e0c403b 100644 --- a/AdoNet.Tests.Unit/AdoNet.Tests.Unit.csproj +++ b/AdoNet.Tests.Unit/AdoNet.Tests.Unit.csproj @@ -8,7 +8,7 @@ - + diff --git a/AdoNet.Tests.Unit/Services/Foundations/Releases/ReleaseServiceTests.Logic.cs b/AdoNet.Tests.Unit/Services/Foundations/Releases/ReleaseServiceTests.Logic.cs new file mode 100644 index 0000000..528d9fd --- /dev/null +++ b/AdoNet.Tests.Unit/Services/Foundations/Releases/ReleaseServiceTests.Logic.cs @@ -0,0 +1,53 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +using ADotNet.Models.Pipelines.Releases.GithubPipelines; +using Moq; +using Xunit; + +namespace AdoNet.Tests.Unit.Services.Foundations.Releases +{ + public partial class ReleaseServiceTests + { + [Fact] + public void ShouldSerializeWriteReleasePipeline() + { + // given + string randomSerializedPipeline = CreateRandomString(); + string serializedGithubPipeline = randomSerializedPipeline; + string randomPath = CreateRandomString(); + string inputPath = randomPath; + + GithubReleasePipeline randomGithubReleasePipeline = + CreateRandomReleasePipeline(); + + GithubReleasePipeline inputGithubReleasePipeline = + randomGithubReleasePipeline; + + this.yamlBrokerMock.Setup(broker => + broker.SerializeToYaml(inputGithubReleasePipeline)) + .Returns(serializedGithubPipeline); + + // when + this.releaseService.SerializeWriteToFile( + inputPath, + inputGithubReleasePipeline); + + // then + + this.yamlBrokerMock.Verify(broker => + broker.SerializeToYaml(inputGithubReleasePipeline), + Times.Once); + + this.filesBrokerMock.Verify(broker => + broker.WriteToFile(inputPath, serializedGithubPipeline), + Times.Once); + + this.yamlBrokerMock.VerifyNoOtherCalls(); + this.filesBrokerMock.VerifyNoOtherCalls(); + } + } +} diff --git a/AdoNet.Tests.Unit/Services/Foundations/Releases/ReleaseServiceTests.Validations.cs b/AdoNet.Tests.Unit/Services/Foundations/Releases/ReleaseServiceTests.Validations.cs new file mode 100644 index 0000000..bbda7b9 --- /dev/null +++ b/AdoNet.Tests.Unit/Services/Foundations/Releases/ReleaseServiceTests.Validations.cs @@ -0,0 +1,87 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +using System; +using ADotNet.Models.Pipelines.Releases.GithubPipelines; +using ADotNet.Models.Pipelines.Releases.GithubPipelines.Exceptions; +using Moq; +using Xunit; + +namespace AdoNet.Tests.Unit.Services.Foundations.Releases +{ + public partial class ReleaseServiceTests + { + [Fact] + public void ShouldThrowValidationExceptionOnSerializeWriteIfPathIsNull() + { + // given + string invalidPath = null; + + GithubReleasePipeline someReleasePipeline = + CreateRandomReleasePipeline(); + + var nullReleasePathException = + new NullReleasePathException(); + + var expectedReleaseValidationException = + new ReleaseValidationException( + nullReleasePathException); + + // when + Action serializeWriteAction = () => + this.releaseService.SerializeWriteToFile(invalidPath, someReleasePipeline); + + // then + Assert.Throws(serializeWriteAction); + + this.yamlBrokerMock.Verify(broker => + broker.SerializeToYaml(It.IsAny()), + Times.Never); + + this.filesBrokerMock.Verify(broker => + broker.WriteToFile(It.IsAny(), It.IsAny()), + Times.Never); + + this.yamlBrokerMock.VerifyNoOtherCalls(); + this.filesBrokerMock.VerifyNoOtherCalls(); + } + + [Fact] + public void ShouldThrowValidationExceptionOnSerializeWriteIfPipelineIsNull() + { + // given + GithubReleasePipeline invalidGithubReleasePipeline = null; + string somePath = CreateRandomString(); + + var nullReleasePipelineException = + new NullReleasePipelineException(); + + var expectedReleaseValidationException = + new ReleaseValidationException( + nullReleasePipelineException); + + // when + Action serializeWriteAction = () => + this.releaseService.SerializeWriteToFile( + somePath, + invalidGithubReleasePipeline); + + // then + Assert.Throws(serializeWriteAction); + + this.yamlBrokerMock.Verify(broker => + broker.SerializeToYaml(It.IsAny()), + Times.Never); + + this.filesBrokerMock.Verify(broker => + broker.WriteToFile(It.IsAny(), It.IsAny()), + Times.Never); + + this.yamlBrokerMock.VerifyNoOtherCalls(); + this.filesBrokerMock.VerifyNoOtherCalls(); + } + } +} diff --git a/AdoNet.Tests.Unit/Services/Foundations/Releases/ReleaseServiceTests.cs b/AdoNet.Tests.Unit/Services/Foundations/Releases/ReleaseServiceTests.cs new file mode 100644 index 0000000..8835c15 --- /dev/null +++ b/AdoNet.Tests.Unit/Services/Foundations/Releases/ReleaseServiceTests.cs @@ -0,0 +1,44 @@ +// --------------------------------------------------------------- +// Copyright (c) Hassan Habib All rights reserved. +// Licensed under the MIT License. +// See License.txt in the project root for license information. +// --------------------------------------------------------------- + +using ADotNet.Brokers.IOs; +using ADotNet.Brokers.Serializers; +using ADotNet.Models.Pipelines.Releases.GithubPipelines; +using ADotNet.Services.Releases; +using Moq; +using Tynamix.ObjectFiller; + +namespace AdoNet.Tests.Unit.Services.Foundations.Releases +{ + public partial class ReleaseServiceTests + { + private readonly Mock yamlBrokerMock; + private readonly Mock filesBrokerMock; + private readonly IReleaseService releaseService; + + public ReleaseServiceTests() + { + this.yamlBrokerMock = new Mock(); + this.filesBrokerMock = new Mock(); + + this.releaseService = new ReleaseService( + yamlBroker: this.yamlBrokerMock.Object, + filesBroker: this.filesBrokerMock.Object); + } + + private static string CreateRandomString() => + new MnemonicString(wordCount: GetRandomNumber()).GetValue(); + + private static GithubReleasePipeline CreateRandomReleasePipeline() => + CreateGithubReleasePipelineFiller().Create(); + + private static int GetRandomNumber() => + new IntRange(min: 2, max: 10).GetValue(); + + private static Filler CreateGithubReleasePipelineFiller() => + new Filler(); + } +}