diff --git a/src/NzbDrone.Core/Indexers/Newznab/NewznabCategoryFieldOptionsConverter.cs b/src/NzbDrone.Core/Indexers/Newznab/NewznabCategoryFieldOptionsConverter.cs index 5b5aee186..94d5a37c4 100644 --- a/src/NzbDrone.Core/Indexers/Newznab/NewznabCategoryFieldOptionsConverter.cs +++ b/src/NzbDrone.Core/Indexers/Newznab/NewznabCategoryFieldOptionsConverter.cs @@ -10,8 +10,10 @@ namespace NzbDrone.Core.Indexers.Newznab { public static List GetFieldSelectOptions(List categories) { - // Ignore categories not relevant for Sonarr - var ignoreCategories = new[] { 0, 1000, 2000, 3000, 4000, 6000, 7000 }; + // Categories not relevant for Sonarr + var ignoreCategories = new[] { 1000, 3000, 4000, 6000, 7000 }; + // And maybe relevant for specific users + var unimportantCategories = new[] { 0, 2000 }; var result = new List(); @@ -38,13 +40,8 @@ namespace NzbDrone.Core.Indexers.Newznab }); } - foreach (var category in categories) + foreach (var category in categories.Where(cat => !ignoreCategories.Contains(cat.Id)).OrderBy(cat => unimportantCategories.Contains(cat.Id)).ThenBy(cat => cat.Id)) { - if (ignoreCategories.Contains(category.Id)) - { - continue; - } - result.Add(new FieldSelectOption { Value = category.Id, @@ -54,7 +51,7 @@ namespace NzbDrone.Core.Indexers.Newznab if (category.Subcategories != null) { - foreach (var subcat in category.Subcategories) + foreach (var subcat in category.Subcategories.OrderBy(cat => cat.Id)) { result.Add(new FieldSelectOption { @@ -67,8 +64,6 @@ namespace NzbDrone.Core.Indexers.Newznab } } - result.Sort((l, r) => l.Value.CompareTo(r.Value)); - return result; } } diff --git a/src/NzbDrone.Integration.Test/ApiTests/IndexerFixture.cs b/src/NzbDrone.Integration.Test/ApiTests/IndexerFixture.cs index 4acf089a4..64ca5dd28 100644 --- a/src/NzbDrone.Integration.Test/ApiTests/IndexerFixture.cs +++ b/src/NzbDrone.Integration.Test/ApiTests/IndexerFixture.cs @@ -1,7 +1,10 @@ using System.Linq; using FluentAssertions; +using Newtonsoft.Json.Linq; using NUnit.Framework; +using NzbDrone.Api.Indexers; using NzbDrone.Core.ThingiProvider; +using Sonarr.Http.ClientSchema; namespace NzbDrone.Integration.Test.ApiTests { @@ -18,5 +21,183 @@ namespace NzbDrone.Integration.Test.ApiTests indexers.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Name)); indexers.Where(c => c.ConfigContract == typeof(NullConfig).Name).Should().OnlyContain(c => c.EnableRss); } + + private IndexerResource GetNewznabSchemav2(string name = null) + { + var schema = Indexers.Schema().First(v => v.Implementation == "Newznab"); + + schema.Name = name; + schema.EnableRss = false; + schema.EnableSearch = false; + + return schema; + } + + private IndexerResource GetNewznabSchemav3(string name = null) + { + var schema = Indexersv3.Schema().First(v => v.Implementation == "Newznab"); + + schema.Name = name; + schema.EnableRss = false; + schema.EnableSearch = false; + + return schema; + } + + private Field GetCategoriesField(IndexerResource resource) + { + var field = resource.Fields.First(v => v.Name == "categories"); + + return field; + } + + [Test] + public void v2_categories_should_be_array() + { + var schema = GetNewznabSchemav2(); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value.Should().BeOfType(); + } + + [Test] + public void v3_categories_should_be_array() + { + var schema = GetNewznabSchemav3(); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value.Should().BeOfType(); + } + + [Test] + public void v2_categories_should_accept_null() + { + var schema = GetNewznabSchemav2("Testv2null"); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value = null; + + var result = Indexers.Post(schema); + + var resultArray = GetCategoriesField(result).Value; + resultArray.Should().BeOfType(); + resultArray.As().Should().BeEmpty(); + } + + [Test] + public void v2_categories_should_accept_emptystring() + { + var schema = GetNewznabSchemav2("Testv2emptystring"); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value = ""; + + var result = Indexers.Post(schema); + + var resultArray = GetCategoriesField(result).Value; + resultArray.Should().BeOfType(); + resultArray.As().Should().BeEmpty(); + } + + [Test] + public void v2_categories_should_accept_string() + { + var schema = GetNewznabSchemav2("Testv2string"); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value = "1000,1010"; + + var result = Indexers.Post(schema); + + var resultArray = GetCategoriesField(result).Value; + resultArray.Should().BeOfType(); + resultArray.As().ToObject().Should().BeEquivalentTo(new[] { 1000, 1010 }); + } + + [Test] + public void v2_categories_should_accept_array() + { + var schema = GetNewznabSchemav2("Testv2array"); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value = new object[] { 1000, 1010 }; + + var result = Indexers.Post(schema); + + var resultArray = GetCategoriesField(result).Value; + resultArray.Should().BeOfType(); + resultArray.As().ToObject().Should().BeEquivalentTo(new[] { 1000, 1010 }); + } + + [Test] + public void v3_categories_should_accept_null() + { + var schema = GetNewznabSchemav3("Testv3null"); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value = null; + + var result = Indexersv3.Post(schema); + + var resultArray = GetCategoriesField(result).Value; + resultArray.Should().BeOfType(); + resultArray.As().Should().BeEmpty(); + } + + [Test] + public void v3_categories_should_accept_emptystring() + { + var schema = GetNewznabSchemav3("Testv3emptystring"); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value = ""; + + var result = Indexersv3.Post(schema); + + var resultArray = GetCategoriesField(result).Value; + resultArray.Should().BeOfType(); + resultArray.As().Should().BeEmpty(); + } + + + [Test] + public void v3_categories_should_accept_string() + { + var schema = GetNewznabSchemav3("Testv3string"); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value = "1000,1010"; + + var result = Indexersv3.Post(schema); + + var resultArray = GetCategoriesField(result).Value; + resultArray.Should().BeOfType(); + resultArray.As().ToObject().Should().BeEquivalentTo(new[] { 1000, 1010 }); + } + + [Test] + public void v3_categories_should_accept_array() + { + var schema = GetNewznabSchemav3("Testv3array"); + + var categoriesField = GetCategoriesField(schema); + + categoriesField.Value = new object[] { 1000, 1010 }; + + var result = Indexersv3.Post(schema); + + var resultArray = GetCategoriesField(result).Value; + resultArray.Should().BeOfType(); + resultArray.As().ToObject().Should().BeEquivalentTo(new[] { 1000, 1010 }); + } } } diff --git a/src/NzbDrone.Integration.Test/Client/IndexerClient.cs b/src/NzbDrone.Integration.Test/Client/IndexerClient.cs index 9d6f9b974..6aaf5bbf7 100644 --- a/src/NzbDrone.Integration.Test/Client/IndexerClient.cs +++ b/src/NzbDrone.Integration.Test/Client/IndexerClient.cs @@ -1,4 +1,5 @@ -using NzbDrone.Api.Indexers; +using System.Collections.Generic; +using NzbDrone.Api.Indexers; using RestSharp; namespace NzbDrone.Integration.Test.Client @@ -9,5 +10,11 @@ namespace NzbDrone.Integration.Test.Client : base(restClient, apiKey) { } + + public List Schema() + { + var request = BuildRequest("/schema"); + return Get>(request); + } } } \ No newline at end of file diff --git a/src/NzbDrone.Integration.Test/IntegrationTestBase.cs b/src/NzbDrone.Integration.Test/IntegrationTestBase.cs index 8350d8d2d..fe682753f 100644 --- a/src/NzbDrone.Integration.Test/IntegrationTestBase.cs +++ b/src/NzbDrone.Integration.Test/IntegrationTestBase.cs @@ -37,6 +37,7 @@ namespace NzbDrone.Integration.Test public abstract class IntegrationTestBase { protected RestClient RestClient { get; private set; } + protected RestClient RestClientv3 { get; private set; } public ClientBase Blacklist; public CommandClient Commands; @@ -45,6 +46,7 @@ namespace NzbDrone.Integration.Test public ClientBase History; public ClientBase HostConfig; public IndexerClient Indexers; + public IndexerClient Indexersv3; public LogsClient Logs; public ClientBase NamingConfig; public NotificationClient Notifications; @@ -100,6 +102,10 @@ namespace NzbDrone.Integration.Test RestClient.AddDefaultHeader("Authentication", ApiKey); RestClient.AddDefaultHeader("X-Api-Key", ApiKey); + RestClientv3 = new RestClient(RootUrl + "api/v3/"); + RestClientv3.AddDefaultHeader("Authentication", ApiKey); + RestClientv3.AddDefaultHeader("X-Api-Key", ApiKey); + Blacklist = new ClientBase(RestClient, ApiKey); Commands = new CommandClient(RestClient, ApiKey); DownloadClients = new DownloadClientClient(RestClient, ApiKey); @@ -107,6 +113,7 @@ namespace NzbDrone.Integration.Test History = new ClientBase(RestClient, ApiKey); HostConfig = new ClientBase(RestClient, ApiKey, "config/host"); Indexers = new IndexerClient(RestClient, ApiKey); + Indexersv3 = new IndexerClient(RestClientv3, ApiKey); Logs = new LogsClient(RestClient, ApiKey); NamingConfig = new ClientBase(RestClient, ApiKey, "config/naming"); Notifications = new NotificationClient(RestClient, ApiKey); diff --git a/src/Sonarr.Http/ClientSchema/SchemaBuilder.cs b/src/Sonarr.Http/ClientSchema/SchemaBuilder.cs index c0ae2001c..f7ccdd5aa 100644 --- a/src/Sonarr.Http/ClientSchema/SchemaBuilder.cs +++ b/src/Sonarr.Http/ClientSchema/SchemaBuilder.cs @@ -217,7 +217,11 @@ namespace Sonarr.Http.ClientSchema { return fieldValue => { - if (fieldValue.GetType() == typeof(JArray)) + if (fieldValue == null) + { + return Enumerable.Empty(); + } + else if (fieldValue.GetType() == typeof(JArray)) { return ((JArray)fieldValue).Select(s => s.Value()); } @@ -232,7 +236,11 @@ namespace Sonarr.Http.ClientSchema { return fieldValue => { - if (fieldValue.GetType() == typeof(JArray)) + if (fieldValue == null) + { + return Enumerable.Empty(); + } + else if (fieldValue.GetType() == typeof(JArray)) { return ((JArray)fieldValue).Select(s => s.Value()); }