refactor: Rework ConfigCreation unit tests

json-serializing-nullable-fields-issue
Robert Dailey 9 months ago
parent 3a50b9fa61
commit bede64eadd

@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using System.IO.Abstractions;
using Recyclarr.Cli.Console.Settings;
using Recyclarr.Common.Extensions;
@ -30,7 +29,6 @@ public class TemplateConfigCreator : IConfigCreator
return settings.Templates.Any();
}
[SuppressMessage("Design", "CA1031:Do not catch general exception types")]
public async Task Create(ICreateConfigSettings settings)
{
_log.Debug("Creating config from templates: {Templates}", settings.Templates);
@ -41,27 +39,9 @@ public class TemplateConfigCreator : IConfigCreator
foreach (var templateFile in matchingTemplateData)
{
var destinationFile = _paths.ConfigsDirectory.File(templateFile.Name);
try
{
if (destinationFile.Exists && !settings.Force)
{
throw new FileExistsException($"{destinationFile} already exists");
}
destinationFile.CreateParentDirectory();
templateFile.CopyTo(destinationFile.FullName, true);
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
if (destinationFile.Exists)
{
_log.Information("Replacing existing file: {Path}", destinationFile);
}
else
{
_log.Information("Created configuration file: {Path}", destinationFile);
}
CopyTemplate(templateFile, settings);
}
catch (FileExistsException e)
{
@ -75,7 +55,31 @@ public class TemplateConfigCreator : IConfigCreator
catch (Exception e)
{
_log.Error(e, "Unable to save configuration template file");
throw;
}
}
}
private void CopyTemplate(IFileInfo templateFile, ICreateConfigSettings settings)
{
var destinationFile = _paths.ConfigsDirectory.File(templateFile.Name);
if (destinationFile.Exists && !settings.Force)
{
throw new FileExistsException($"{destinationFile} already exists");
}
destinationFile.CreateParentDirectory();
templateFile.CopyTo(destinationFile.FullName, true);
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
if (destinationFile.Exists)
{
_log.Information("Replacing existing file: {Path}", destinationFile);
}
else
{
_log.Information("Created configuration file: {Path}", destinationFile);
}
}
}

@ -3,10 +3,8 @@ using System.IO.Abstractions.Extensions;
using Recyclarr.Cli.Console.Settings;
using Recyclarr.Cli.Processors.Config;
using Recyclarr.Cli.TestLibrary;
using Recyclarr.TrashLib.Config;
using Recyclarr.TrashLib.Config.Services;
using Recyclarr.TrashLib.ExceptionTypes;
using Recyclarr.TrashLib.Repo;
using Recyclarr.TrashLib.Startup;
namespace Recyclarr.Cli.Tests.Processors.Config;
@ -35,110 +33,44 @@ public class TemplateConfigCreatorTest : CliIntegrationFixture
}
[Test, AutoMockData]
public void Throw_when_file_exists_and_not_forced(
public async Task No_replace_when_file_exists_and_not_forced(
[Frozen] IConfigTemplateGuideService templates,
MockFileSystem fs,
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs,
[Frozen] IAppPaths paths,
ICreateConfigSettings settings,
TemplateConfigCreator sut)
{
templates.LoadTemplateData().Returns(new[]
{
new TemplatePath
{
Id = "template1",
TemplateFile = fs.CurrentDirectory().File("template-file1.yml"),
Service = SupportedServices.Radarr
}
});
var templateFile = fs.CurrentDirectory().File("template-file1.yml");
var destFile = paths.ConfigsDirectory.File(templateFile.Name);
fs.AddFile(templateFile, new MockFileData("a"));
fs.AddFile(destFile, new MockFileData("b"));
settings.Force.Returns(false);
settings.Templates.Returns(new[]
{
"template1"
});
settings.Path.Returns(templateFile.FullName);
var act = () => sut.Create(settings);
await sut.Create(settings);
act.Should().ThrowAsync<FileExistsException>();
fs.GetFile(destFile).TextContents.Should().Be("b");
}
[Test, AutoMockData]
public void No_throw_when_file_exists_and_forced(
public async Task No_throw_when_file_exists_and_forced(
[Frozen] IConfigTemplateGuideService templates,
MockFileSystem fs,
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs,
[Frozen] IAppPaths paths,
ICreateConfigSettings settings,
TemplateConfigCreator sut)
{
templates.LoadTemplateData().Returns(new[]
{
new TemplatePath
{
Id = "template1",
TemplateFile = fs.CurrentDirectory().File("template-file1.yml"),
Service = SupportedServices.Radarr
}
});
var templateFile = fs.CurrentDirectory().File("template-file1.yml");
fs.AddEmptyFile(templateFile);
fs.AddEmptyFile(paths.ConfigsDirectory.File(templateFile.Name));
settings.Force.Returns(true);
settings.Templates.Returns(new[]
{
"template1"
});
settings.Path.Returns(templateFile.FullName);
var act = () => sut.Create(settings);
act.Should().NotThrowAsync();
}
[Test]
public async Task Template_id_matching_works()
{
const string templatesJson =
"""
{
"radarr": [
{
"template": "template-file1.yml",
"id": "template1"
}
],
"sonarr": [
{
"template": "template-file2.yml",
"id": "template2"
},
{
"template": "template-file3.yml",
"id": "template3"
}
]
}
""";
var repo = Resolve<IConfigTemplatesRepo>();
Fs.AddFile(repo.Path.File("templates.json"), new MockFileData(templatesJson));
Fs.AddEmptyFile(repo.Path.File("template-file1.yml"));
Fs.AddEmptyFile(repo.Path.File("template-file2.yml"));
// This one shouldn't show up in the result because the user didn't ask for it
Fs.AddEmptyFile(repo.Path.File("template-file3.yml"));
var settings = Substitute.For<ICreateConfigSettings>();
settings.Templates.Returns(new[]
{
"template1",
"template2",
// This one shouldn't show up in the results because:
// User specified it, but no template file exists for it.
"template4"
});
var sut = Resolve<TemplateConfigCreator>();
await sut.Create(settings);
Fs.AllFiles.Should().Contain(new[]
{
Paths.ConfigsDirectory.File("template-file1.yml").FullName,
Paths.ConfigsDirectory.File("template-file2.yml").FullName
});
await act.Should().NotThrowAsync();
}
}

@ -0,0 +1,123 @@
using System.IO.Abstractions;
using System.IO.Abstractions.Extensions;
using Recyclarr.Cli.Console.Commands;
using Recyclarr.Cli.Console.Settings;
using Recyclarr.Cli.Processors.Config;
using Recyclarr.Cli.TestLibrary;
using Recyclarr.TrashLib.ExceptionTypes;
using Recyclarr.TrashLib.Repo;
namespace Recyclarr.Cli.Tests.Processors;
[TestFixture]
[Parallelizable(ParallelScope.All)]
public class ConfigCreationProcessorIntegrationTest : CliIntegrationFixture
{
[Test]
public async Task Config_file_created_when_using_default_path()
{
var repo = Resolve<IConfigTemplatesRepo>();
Fs.AddFile(repo.Path.File("templates.json"), new MockFileData("{}"));
var sut = Resolve<ConfigCreationProcessor>();
await sut.Process(new ConfigCreateCommand.CliSettings
{
Path = null
});
var file = Fs.GetFile(Paths.AppDataDirectory.File("recyclarr.yml"));
file.Should().NotBeNull();
file.Contents.Should().NotBeEmpty();
}
[Test]
public async Task Config_file_created_when_using_user_specified_path()
{
var sut = Resolve<ConfigCreationProcessor>();
var settings = new ConfigCreateCommand.CliSettings
{
Path = Fs.CurrentDirectory()
.SubDirectory("user")
.SubDirectory("specified")
.File("file.yml")
.FullName
};
await sut.Process(settings);
var file = Fs.GetFile(settings.Path);
file.Should().NotBeNull();
file.Contents.Should().NotBeEmpty();
}
[Test]
public async Task Should_throw_if_file_already_exists()
{
var sut = Resolve<ConfigCreationProcessor>();
var settings = new ConfigCreateCommand.CliSettings
{
Path = Fs.CurrentDirectory().File("file.yml").FullName
};
Fs.AddEmptyFile(settings.Path);
var act = () => sut.Process(settings);
await act.Should().ThrowAsync<FileExistsException>();
}
[Test]
public async Task Template_id_matching_works()
{
const string templatesJson =
"""
{
"radarr": [
{
"template": "template-file1.yml",
"id": "template1"
}
],
"sonarr": [
{
"template": "template-file2.yml",
"id": "template2"
},
{
"template": "template-file3.yml",
"id": "template3"
}
]
}
""";
var repo = Resolve<IConfigTemplatesRepo>();
Fs.AddFile(repo.Path.File("templates.json"), new MockFileData(templatesJson));
Fs.AddEmptyFile(repo.Path.File("template-file1.yml"));
Fs.AddEmptyFile(repo.Path.File("template-file2.yml"));
// This one shouldn't show up in the result because the user didn't ask for it
Fs.AddEmptyFile(repo.Path.File("template-file3.yml"));
var settings = Substitute.For<ICreateConfigSettings>();
settings.Templates.Returns(new[]
{
"template1",
"template2",
// This one shouldn't show up in the results because:
// User specified it, but no template file exists for it.
"template4"
});
var sut = Resolve<ConfigCreationProcessor>();
await sut.Process(settings);
Fs.AllFiles.Should().Contain(new[]
{
Paths.ConfigsDirectory.File("template-file1.yml").FullName,
Paths.ConfigsDirectory.File("template-file2.yml").FullName
});
}
}

@ -1,72 +1,16 @@
using System.Diagnostics.CodeAnalysis;
using System.IO.Abstractions;
using System.IO.Abstractions.Extensions;
using Autofac.Extras.Ordering;
using AutoFixture;
using Recyclarr.Cli.Console.Commands;
using Recyclarr.Cli.Processors.Config;
using Recyclarr.Cli.TestLibrary;
using Recyclarr.TrashLib.ExceptionTypes;
namespace Recyclarr.Cli.Tests.Processors;
[TestFixture]
[Parallelizable(ParallelScope.All)]
public class ConfigCreationProcessorTest : CliIntegrationFixture
public class ConfigCreationProcessorTest
{
[Test]
public async Task Config_file_created_when_using_default_path()
{
var sut = Resolve<ConfigCreationProcessor>();
await sut.Process(new ConfigCreateCommand.CliSettings
{
Path = null
});
var file = Fs.GetFile(Paths.AppDataDirectory.File("recyclarr.yml"));
file.Should().NotBeNull();
file.Contents.Should().NotBeEmpty();
}
[Test]
public async Task Config_file_created_when_using_user_specified_path()
{
var sut = Resolve<ConfigCreationProcessor>();
var settings = new ConfigCreateCommand.CliSettings
{
Path = Fs.CurrentDirectory()
.SubDirectory("user")
.SubDirectory("specified")
.File("file.yml")
.FullName
};
await sut.Process(settings);
var file = Fs.GetFile(settings.Path);
file.Should().NotBeNull();
file.Contents.Should().NotBeEmpty();
}
[Test]
public async Task Should_throw_if_file_already_exists()
{
var sut = Resolve<ConfigCreationProcessor>();
var settings = new ConfigCreateCommand.CliSettings
{
Path = Fs.CurrentDirectory().File("file.yml").FullName
};
Fs.AddEmptyFile(settings.Path);
var act = () => sut.Process(settings);
await act.Should().ThrowAsync<FileExistsException>();
}
[SuppressMessage("Performance", "CA1812", Justification =
"Used implicitly by test methods in this class")]
private sealed class EmptyOrderedEnumerable : ICustomization

Loading…
Cancel
Save