refactor: Use raw string literals for multi-line strings

json-serializing-nullable-fields-issue
Robert Dailey 9 months ago
parent c3b7e973b2
commit c190d5e6d6

@ -2,162 +2,167 @@ namespace Recyclarr.Cli.Pipelines.ReleaseProfile.Api.Schemas;
public static class SonarrReleaseProfileSchema
{
public static string V1 => @"{
'definitions': {
'SonarrPreferredTerm': {
'type': [
'object',
'null'
],
'properties': {
'key': {
'type': [
'string',
'null'
]
},
'value': {
'type': 'integer'
public static string V1 =>
"""
{
"definitions": {
"SonarrPreferredTerm": {
"type": [
"object",
"null"
],
"properties": {
"key": {
"type": [
"string",
"null"
]
},
"value": {
"type": "integer"
}
}
}
},
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"name": {
"type": [
"string",
"null"
]
},
"required": {
"type": [
"string",
"null"
]
},
"ignored": {
"type": [
"string",
"null"
]
},
"preferred": {
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/SonarrPreferredTerm"
}
},
"includePreferredWhenRenaming": {
"type": "boolean"
},
"indexerId": {
"type": "integer"
},
"tags": {
"type": [
"array",
"null"
],
"items": {
"type": "integer"
}
}
}
}
}
}
},
'type': 'object',
'properties': {
'id': {
'type': 'integer'
},
'enabled': {
'type': 'boolean'
},
'name': {
'type': [
'string',
'null'
]
},
'required': {
'type': [
'string',
'null'
]
},
'ignored': {
'type': [
'string',
'null'
]
},
'preferred': {
'type': [
'array',
'null'
],
'items': {
'$ref': '#/definitions/SonarrPreferredTerm'
}
},
'includePreferredWhenRenaming': {
'type': 'boolean'
},
'indexerId': {
'type': 'integer'
},
'tags': {
'type': [
'array',
'null'
],
'items': {
'type': 'integer'
}
}
}
}";
""";
public static string V2 => @"{
'definitions': {
'SonarrPreferredTerm': {
'type': [
'object',
'null'
],
'properties': {
'key': {
'type': [
'string',
'null'
]
},
'value': {
'type': 'integer'
public static string V2 =>
"""
{
"definitions": {
"SonarrPreferredTerm": {
"type": [
"object",
"null"
],
"properties": {
"key": {
"type": [
"string",
"null"
]
},
"value": {
"type": "integer"
}
}
}
},
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"name": {
"type": [
"string",
"null"
]
},
"required": {
"type": [
"array",
"null"
],
"items": {
"type": [
"string",
"null"
]
}
},
"ignored": {
"type": [
"array",
"null"
],
"items": {
"type": [
"string",
"null"
]
}
},
"preferred": {
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/SonarrPreferredTerm"
}
},
"includePreferredWhenRenaming": {
"type": "boolean"
},
"indexerId": {
"type": "integer"
},
"tags": {
"type": [
"array",
"null"
],
"items": {
"type": "integer"
}
}
}
}
}
}
},
'type': 'object',
'properties': {
'id': {
'type': 'integer'
},
'enabled': {
'type': 'boolean'
},
'name': {
'type': [
'string',
'null'
]
},
'required': {
'type': [
'array',
'null'
],
'items': {
'type': [
'string',
'null'
]
}
},
'ignored': {
'type': [
'array',
'null'
],
'items': {
'type': [
'string',
'null'
]
}
},
'preferred': {
'type': [
'array',
'null'
],
'items': {
'$ref': '#/definitions/SonarrPreferredTerm'
}
},
'includePreferredWhenRenaming': {
'type': 'boolean'
},
'indexerId': {
'type': 'integer'
},
'tags': {
'type': [
'array',
'null'
],
'items': {
'type': 'integer'
}
}
}
}
";
""";
}

@ -26,10 +26,11 @@ public class BaseCommandSetupIntegrationTest : CliIntegrationFixture
{
const int maxFiles = 25;
Fs.AddFile(Paths.AppDataDirectory.File("settings.yml").FullName, new MockFileData($@"
log_janitor:
max_files: {maxFiles}
"));
Fs.AddFile(Paths.AppDataDirectory.File("settings.yml").FullName, new MockFileData(
$"""
log_janitor:
max_files: {maxFiles}
"""));
for (var i = 0; i < maxFiles + 20; ++i)
{

@ -113,9 +113,12 @@ public class ServiceCacheTest
var expectedFile = fs.GetFile(testJsonPath);
expectedFile.Should().NotBeNull();
expectedFile.TextContents.Should().Be(@"{
""test_value"": ""Foo""
}");
expectedFile.TextContents.Should().Be(
"""
{
"test_value": "Foo"
}
""");
}
[Test, AutoMockData]
@ -184,18 +187,19 @@ public class ServiceCacheTest
IServiceConfiguration config,
ServiceCache sut)
{
const string cacheJson = @"
{
'version': 1,
'trash_id_mappings': [
{
'custom_format_name': '4K Remaster',
'trash_id': 'eca37840c13c6ef2dd0262b141a5482f',
'custom_format_id': 4
}
]
}
";
const string cacheJson =
"""
{
'version': 1,
'trash_id_mappings': [
{
'custom_format_name': '4K Remaster',
'trash_id': 'eca37840c13c6ef2dd0262b141a5482f',
'custom_format_id': 4
}
]
}
""";
fs.AddFile("cacheFile.json", new MockFileData(cacheJson));
storage.CalculatePath(default!, default!).ReturnsForAnyArgs(fs.FileInfo.New("cacheFile.json"));

@ -13,32 +13,33 @@ public class FieldsArrayJsonConverterTest
{
var serializer = new NewtonsoftJsonSerializer(ServiceJsonSerializerFactory.Settings);
const string json = @"
{
'fields': [
{
'order': 0,
'name': 'min',
'label': 'Minimum Size',
'unit': 'GB',
'helpText': 'Release must be greater than this size',
'value': 25,
'type': 'number',
'advanced': false
},
{
'order': 1,
'name': 'max',
'label': 'Maximum Size',
'unit': 'GB',
'helpText': 'Release must be less than or equal to this size',
'value': 40,
'type': 'number',
'advanced': false
}
]
}
";
const string json =
"""
{
"fields": [
{
"order": 0,
"name": "min",
"label": "Minimum Size",
"unit": "GB",
"helpText": "Release must be greater than this size",
"value": 25,
"type": "number",
"advanced": false
},
{
"order": 1,
"name": "max",
"label": "Maximum Size",
"unit": "GB",
"helpText": "Release must be less than or equal to this size",
"value": 40,
"type": "number",
"advanced": false
}
]
}
""";
var result = serializer.Deserialize<CustomFormatSpecificationData>(json);
result.Fields.Should().BeEquivalentTo(new[]
@ -59,20 +60,21 @@ public class FieldsArrayJsonConverterTest
{
var serializer = new NewtonsoftJsonSerializer(ServiceJsonSerializerFactory.Settings);
const string json = @"
{
'fields': {
'order': 0,
'name': 'min',
'label': 'Minimum Size',
'unit': 'GB',
'helpText': 'Release must be greater than this size',
'value': 25,
'type': 'number',
'advanced': false
}
}
";
const string json =
"""
{
"fields": {
"order": 0,
"name": "min",
"label": "Minimum Size",
"unit": "GB",
"helpText": "Release must be greater than this size",
"value": 25,
"type": "number",
"advanced": false
}
}
""";
var result = serializer.Deserialize<CustomFormatSpecificationData>(json);
result.Fields.Should().BeEquivalentTo(new[]
@ -89,11 +91,12 @@ public class FieldsArrayJsonConverterTest
{
var serializer = new NewtonsoftJsonSerializer(ServiceJsonSerializerFactory.Settings);
const string json = @"
{
'fields': 0
}
";
const string json =
"""
{
"fields": 0
}
""";
var act = () => serializer.Deserialize<CustomFormatSpecificationData>(json);
act.Should().Throw<InvalidOperationException>();

@ -17,17 +17,19 @@ public class QualityGuideServiceTest : CliIntegrationFixture
public void Get_data_for_service(SupportedServices service, string serviceDir)
{
var repo = Resolve<ITrashGuidesRepo>();
const string metadataJson = @"
{
'json_paths': {
'radarr': {
'qualities': ['docs/json/radarr/quality-size']
},
'sonarr': {
'qualities': ['docs/json/sonarr/quality-size']
}
}
}";
const string metadataJson =
"""
{
"json_paths": {
"radarr": {
"qualities": ["docs/json/radarr/quality-size"]
},
"sonarr": {
"qualities": ["docs/json/sonarr/quality-size"]
}
}
}
""";
Fs.AddFile(repo.Path.File("metadata.json"), new MockFileData(metadataJson));

@ -17,12 +17,13 @@ public class ConfigManipulatorTest : CliIntegrationFixture
var src = Fs.CurrentDirectory().File("template.yml");
var dst = Fs.CurrentDirectory().SubDir("one", "two", "three").File("config.yml");
const string yamlData = @"
sonarr:
instance1:
base_url: http://localhost:80
api_key: 123abc
";
const string yamlData =
"""
sonarr:
instance1:
base_url: http://localhost:80
api_key: 123abc
""";
Fs.AddFile(src, new MockFileData(yamlData));
@ -38,11 +39,12 @@ sonarr:
var src = Fs.CurrentDirectory().File("template.yml");
var dst = Fs.CurrentDirectory().File("config.yml");
const string yamlData = @"
sonarr:
instance1:
invalid: yaml
";
const string yamlData =
"""
sonarr:
instance1:
invalid: yaml
""";
Fs.AddFile(src, new MockFileData(yamlData));

@ -93,25 +93,27 @@ public class TemplateConfigCreatorTest : CliIntegrationFixture
[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'
}
]
}";
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));

@ -14,11 +14,12 @@ public class ServiceCompatibilityIntegrationTest : CliIntegrationFixture
var sut = Resolve<SettingsProvider>();
// For this test, it doesn't really matter if the YAML data matches what SettingsValue expects.
// This test only ensures that the data deserialized is from the actual correct file.
const string yamlData = @"
repositories:
trash_guides:
clone_url: http://the_url.com
";
const string yamlData =
"""
repositories:
trash_guides:
clone_url: http://the_url.com
""";
Fs.AddFile(Paths.AppDataDirectory.File("settings.yml"), new MockFileData(yamlData));

@ -58,12 +58,13 @@ public class ConfigSaverTest : TrashLibIntegrationFixture
sut.Save(config, destFile);
var expectedYaml = @"
radarr:
instance1:
api_key: apikey
base_url: http://baseurl.com
".TrimStart();
var expectedYaml =
"""
radarr:
instance1:
api_key: apikey
base_url: http://baseurl.com
""";
var expectedFile = Fs.GetFile(destFile);
expectedFile.Should().NotBeNull();

@ -17,12 +17,13 @@ public class ConfigurationLoaderEnvVarTest : TrashLibIntegrationFixture
var sut = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance:
api_key: !env_var SONARR_API_KEY
base_url: !env_var SONARR_URL http://sonarr:1233
";
const string testYml =
"""
sonarr:
instance:
api_key: !env_var SONARR_API_KEY
base_url: !env_var SONARR_URL http://sonarr:1233
""";
var config = sut.Load(testYml);
@ -41,12 +42,13 @@ sonarr:
{
var sut = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance:
base_url: !env_var SONARR_URL http://sonarr:1233
api_key: value
";
const string testYml =
"""
sonarr:
instance:
base_url: !env_var SONARR_URL http://sonarr:1233
api_key: value
""";
var config = sut.Load(testYml);
config.Should().BeEquivalentTo(new[]
@ -66,12 +68,13 @@ sonarr:
var sut = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance:
base_url: !env_var SONARR_URL http://somevalue
api_key: value
";
const string testYml =
"""
sonarr:
instance:
base_url: !env_var SONARR_URL http://somevalue
api_key: value
""";
var config = sut.Load(testYml);
config.Should().BeEquivalentTo(new[]
@ -91,12 +94,13 @@ sonarr:
var sut = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance:
base_url: !env_var SONARR_URL ""http://theurl""
api_key: !env_var SONARR_API 'the key'
";
const string testYml =
"""
sonarr:
instance:
base_url: !env_var SONARR_URL "http://theurl"
api_key: !env_var SONARR_API 'the key'
""";
var config = sut.Load(testYml);
config.Should().BeEquivalentTo(new[]
@ -114,12 +118,13 @@ sonarr:
{
var sut = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance:
base_url: !env_var SONARR_URL http://somevalue
api_key: value
";
const string testYml =
"""
sonarr:
instance:
base_url: !env_var SONARR_URL http://somevalue
api_key: value
""";
var config = sut.Load(testYml);
config.Should().BeEquivalentTo(new[]
@ -136,12 +141,13 @@ sonarr:
{
var sut = Resolve<ConfigurationLoader>();
const string testYml = $@"
sonarr:
instance:
base_url: !env_var SONARR_URL {"\t"}http://somevalue
api_key: value
";
const string testYml =
$"""
sonarr:
instance:
base_url: !env_var SONARR_URL {"\t"}http://somevalue
api_key: value
""";
var config = sut.Load(testYml);
config.Should().BeEquivalentTo(new[]
@ -158,12 +164,13 @@ sonarr:
{
var sut = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance:
base_url: !env_var SONARR_URL
api_key: value
";
const string testYml =
"""
sonarr:
instance:
base_url: !env_var SONARR_URL
api_key: value
""";
var result = sut.Load(testYml);
result.Should().BeEmpty();

@ -15,21 +15,23 @@ public class ConfigurationLoaderSecretsTest : TrashLibIntegrationFixture
{
var configLoader = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance1:
api_key: !secret api_key
base_url: !secret 123GARBAGE_
release_profiles:
- trash_ids:
- !secret secret_rp
";
const string secretsYml = @"
api_key: 95283e6b156c42f3af8a9b16173f876b
123GARBAGE_: 'https://radarr:7878'
secret_rp: 1234567
";
const string testYml =
"""
sonarr:
instance1:
api_key: !secret api_key
base_url: !secret 123GARBAGE_
release_profiles:
- trash_ids:
- !secret secret_rp
""";
const string secretsYml =
"""
api_key: 95283e6b156c42f3af8a9b16173f876b
123GARBAGE_: 'https://radarr:7878'
secret_rp: 1234567
""";
Fs.AddFile(Paths.AppDataDirectory.File("secrets.yml").FullName, new MockFileData(secretsYml));
var expected = new[]
@ -59,12 +61,13 @@ secret_rp: 1234567
using var logContext = TestCorrelator.CreateContext();
var configLoader = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance2:
api_key: !secret api_key
base_url: fake_url
";
const string testYml =
"""
sonarr:
instance2:
api_key: !secret api_key
base_url: fake_url
""";
const string secretsYml = "no_api_key: 95283e6b156c42f3af8a9b16173f876b";
@ -79,12 +82,13 @@ sonarr:
{
var configLoader = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance3:
api_key: !secret api_key
base_url: fake_url
";
const string testYml =
"""
sonarr:
instance3:
api_key: !secret api_key
base_url: fake_url
""";
var result = configLoader.Load(() => new StringReader(testYml), SupportedServices.Sonarr);
result.Should().BeEmpty();
@ -95,12 +99,13 @@ sonarr:
{
var configLoader = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance4:
api_key: !secret { property: value }
base_url: fake_url
";
const string testYml =
"""
sonarr:
instance4:
api_key: !secret { property: value }
base_url: fake_url
""";
var result = configLoader.Load(() => new StringReader(testYml), SupportedServices.Sonarr);
result.Should().BeEmpty();
@ -111,13 +116,14 @@ sonarr:
{
var configLoader = Resolve<ConfigurationLoader>();
const string testYml = @"
sonarr:
instance5:
api_key: fake_key
base_url: fake_url
release_profiles: !secret bogus_profile
";
const string testYml =
"""
sonarr:
instance5:
api_key: fake_key
base_url: fake_url
release_profiles: !secret bogus_profile
""";
const string secretsYml = @"bogus_profile: 95283e6b156c42f3af8a9b16173f876b";

@ -37,10 +37,12 @@ public class ConfigurationLoaderTest : TrashLibIntegrationFixture
static string MockYaml(string sectionName, params object[] args)
{
var str = new StringBuilder($"{sectionName}:");
const string templateYaml = @"
instance{1}:
base_url: http://{0}
api_key: abc";
const string templateYaml =
"""
instance{1}:
base_url: http://{0}
api_key: abc
""";
var counter = 0;
str.Append(args.Aggregate("", (current, p) => current + templateYaml.FormatWith(p, counter++)));
@ -124,12 +126,13 @@ public class ConfigurationLoaderTest : TrashLibIntegrationFixture
using var logContext = TestCorrelator.CreateContext();
var sut = Resolve<ConfigurationLoader>();
const string testYml = @"
not_wanted:
instance:
base_url: abc
api_key: xyz
";
const string testYml =
"""
not_wanted:
instance:
base_url: abc
api_key: xyz
""";
sut.Load(testYml, SupportedServices.Sonarr);

Loading…
Cancel
Save