refactor: Move yaml deserializer creation logic to a factory

pull/47/head
Robert Dailey 2 years ago
parent 88633392a9
commit 592d217020

@ -5,22 +5,28 @@ using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Text;
using Autofac;
using AutoFixture.NUnit3;
using Common;
using Common.Extensions;
using FluentAssertions;
using FluentValidation;
using FluentValidation.Results;
using JetBrains.Annotations;
using NSubstitute;
using NUnit.Framework;
using TestLibrary;
using TestLibrary.AutoFixture;
using TestLibrary.NSubstitute;
using Trash.Config;
using TrashLib.Config;
using TrashLib.Config.Services;
using TrashLib.Sonarr.Config;
using TrashLib.Sonarr.ReleaseProfile;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.ObjectFactories;
namespace Trash.Tests.Config;
namespace Trash.Tests.Config.Services;
[TestFixture]
[Parallelizable(ParallelScope.All)]
@ -32,16 +38,30 @@ public class ConfigurationLoaderTest
return new StringReader(testData.ReadData(file));
}
private static IContainer BuildContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<DefaultObjectFactory>().As<IObjectFactory>();
builder.RegisterType<YamlDeserializerFactory>().As<IYamlDeserializerFactory>();
return builder.Build();
}
[UsedImplicitly]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("Microsoft.Design", "CA1034",
Justification = "YamlDotNet requires this type to be public so it may access it")]
[SuppressMessage("Performance", "CA1822", MessageId = "Mark members as static")]
public class TestConfig : IServiceConfiguration
{
public string BaseUrl => "";
public string ApiKey => "";
}
[Test]
public void Load_many_iterations_of_config()
[Test, AutoMockData(typeof(ConfigurationLoaderTest), nameof(BuildContainer))]
public void Load_many_iterations_of_config(
[Frozen] IFileSystem fs,
[Frozen] IConfigurationProvider provider,
ConfigurationLoader<SonarrConfiguration> loader)
{
static StreamReader MockYaml(params object[] args)
{
@ -51,23 +71,7 @@ public class ConfigurationLoaderTest
return StreamBuilder.FromString(str.ToString());
}
var fs = Substitute.For<IFileSystem>();
fs.File.OpenText(Arg.Any<string>())
.Returns(MockYaml(1, 2), MockYaml(3));
var provider = Substitute.For<IConfigurationProvider>();
// var objectFactory = Substitute.For<IObjectFactory>();
// objectFactory.Create(Arg.Any<Type>())
// .Returns(t => Substitute.For(new[] {(Type)t[0]}, Array.Empty<object>()));
var actualActiveConfigs = new List<SonarrConfiguration>();
#pragma warning disable NS1004
provider.ActiveConfiguration = Arg.Do<SonarrConfiguration>(a => actualActiveConfigs.Add(a));
#pragma warning restore NS1004
var validator = Substitute.For<IValidator<SonarrConfiguration>>();
var loader =
new ConfigurationLoader<SonarrConfiguration>(provider, fs, new DefaultObjectFactory(), validator);
fs.File.OpenText(Arg.Any<string>()).Returns(MockYaml(1, 2), MockYaml(3));
var fakeFiles = new List<string>
{
@ -85,19 +89,13 @@ public class ConfigurationLoaderTest
var actual = loader.LoadMany(fakeFiles, "sonarr").ToList();
actual.Should().BeEquivalentTo(expected);
actualActiveConfigs.Should().BeEquivalentTo(expected, op => op.WithoutStrictOrdering());
provider.Received(3).ActiveConfiguration =
Verify.That<SonarrConfiguration>(x => expected.Should().ContainEquivalentOf(x));
}
[Test]
public void Parse_using_stream()
[Test, AutoMockData(typeof(ConfigurationLoaderTest), nameof(BuildContainer))]
public void Parse_using_stream(ConfigurationLoader<SonarrConfiguration> configLoader)
{
var validator = Substitute.For<IValidator<SonarrConfiguration>>();
var configLoader = new ConfigurationLoader<SonarrConfiguration>(
Substitute.For<IConfigurationProvider>(),
Substitute.For<IFileSystem>(),
new DefaultObjectFactory(),
validator);
var configs = configLoader.LoadFromStream(GetResourceData("Load_UsingStream_CorrectParsing.yml"), "sonarr");
configs.Should()
@ -130,16 +128,11 @@ public class ConfigurationLoaderTest
});
}
[Test]
public void Throw_when_validation_fails()
[Test, AutoMockData]
public void Throw_when_validation_fails(
[Frozen] IValidator<TestConfig> validator,
ConfigurationLoader<TestConfig> configLoader)
{
var validator = Substitute.For<IValidator<TestConfig>>();
var configLoader = new ConfigurationLoader<TestConfig>(
Substitute.For<IConfigurationProvider>(),
Substitute.For<IFileSystem>(),
new DefaultObjectFactory(),
validator);
// force the validator to return a validation error
validator.Validate(Arg.Any<TestConfig>()).Returns(new ValidationResult
{
@ -155,16 +148,9 @@ fubar:
act.Should().Throw<ConfigurationException>();
}
[Test]
public void Validation_success_does_not_throw()
[Test, AutoMockData]
public void Validation_success_does_not_throw(ConfigurationLoader<TestConfig> configLoader)
{
var validator = Substitute.For<IValidator<TestConfig>>();
var configLoader = new ConfigurationLoader<TestConfig>(
Substitute.For<IConfigurationProvider>(),
Substitute.For<IFileSystem>(),
new DefaultObjectFactory(),
validator);
var testYml = @"
fubar:
- api_key: abc

@ -2,14 +2,12 @@
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using Common.YamlDotNet;
using FluentValidation;
using TrashLib.Config;
using TrashLib.Config.Services;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace Trash.Config;
@ -24,18 +22,13 @@ public class ConfigurationLoader<T> : IConfigurationLoader<T>
public ConfigurationLoader(
IConfigurationProvider configProvider,
IFileSystem fileSystem,
IObjectFactory objectFactory,
IYamlDeserializerFactory yamlFactory,
IValidator<T> validator)
{
_configProvider = configProvider;
_fileSystem = fileSystem;
_validator = validator;
_deserializer = new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.WithTypeConverter(new YamlNullableEnumTypeConverter())
.WithObjectFactory(objectFactory)
.Build();
_deserializer = yamlFactory.Create();
}
public IEnumerable<T> Load(string propertyName, string configSection)

@ -17,5 +17,7 @@ public class ConfigAutofacModule : Module
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.AsClosedTypesOf(typeof(IValidator<>))
.AsImplementedInterfaces();
builder.RegisterType<YamlDeserializerFactory>().As<IYamlDeserializerFactory>();
}
}

@ -0,0 +1,9 @@
using YamlDotNet.Serialization;
namespace TrashLib.Config;
public interface IYamlSerializerFactory
{
IDeserializer CreateDeserializer();
ISerializer CreateSerializer();
}

@ -0,0 +1,33 @@
using Common.YamlDotNet;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace TrashLib.Config;
public class YamlSerializerFactory : IYamlSerializerFactory
{
private readonly IObjectFactory _objectFactory;
public YamlSerializerFactory(IObjectFactory objectFactory)
{
_objectFactory = objectFactory;
}
public IDeserializer CreateDeserializer()
{
return new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.WithTypeConverter(new YamlNullableEnumTypeConverter())
.WithObjectFactory(_objectFactory)
.Build();
}
public ISerializer CreateSerializer()
{
return new SerializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.WithTypeConverter(new YamlNullableEnumTypeConverter())
.Build();
}
}
Loading…
Cancel
Save