context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using Jackett.Common.Models;
  using Jackett.Test.TestHelpers;
  using NUnit.Framework;
  using Assert = NUnit.Framework.Assert;
  
  namespace Jackett.Test.Common.Models
  {
      [TestFixture]
      public class TorznabCapabilitiesTests
      {
          [Test]
          public void TestConstructors()
          {
              var torznabCaps = new TorznabCapabilities();
              Assert.True(torznabCaps.SearchAvailable);
  
              Assert.IsEmpty(torznabCaps.TvSearchParams);
              Assert.False(torznabCaps.TvSearchAvailable);
              Assert.False(torznabCaps.TvSearchSeasonAvailable);
              Assert.False(torznabCaps.TvSearchEpAvailable);
              Assert.False(torznabCaps.TvSearchImdbAvailable);
              Assert.False(torznabCaps.TvSearchTvdbAvailable);
              Assert.False(torznabCaps.TvSearchTvRageAvailable);
  
              Assert.IsEmpty(torznabCaps.MovieSearchParams);
              Assert.False(torznabCaps.MovieSearchAvailable);
              Assert.False(torznabCaps.MovieSearchImdbAvailable);
              Assert.False(torznabCaps.MovieSearchTmdbAvailable);
  
              Assert.IsEmpty(torznabCaps.MusicSearchParams);
              Assert.False(torznabCaps.MusicSearchAvailable);
              Assert.False(torznabCaps.MusicSearchAlbumAvailable);
              Assert.False(torznabCaps.MusicSearchArtistAvailable);
              Assert.False(torznabCaps.MusicSearchLabelAvailable);
              Assert.False(torznabCaps.MusicSearchYearAvailable);
  
              Assert.IsEmpty(torznabCaps.BookSearchParams);
              Assert.False(torznabCaps.BookSearchAvailable);
              Assert.False(torznabCaps.BookSearchTitleAvailable);
              Assert.False(torznabCaps.BookSearchAuthorAvailable);
  
              Assert.IsEmpty(torznabCaps.Categories.GetTorznabCategoryTree());
              Assert.IsEmpty(torznabCaps.Categories.GetTrackerCategories());
          }
  
          [Test]
          public void TestParseCardigannSearchModes()
          {
              var torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string> {"q"}},
                  {"tv-search", new List<string> {"q"}},
                  {"movie-search", new List<string> {"q"}},
                  {"music-search", new List<string> {"q"}},
                  {"book-search", new List<string> {"q"}}
              });
              Assert.True(torznabCaps.SearchAvailable);
              Assert.True(torznabCaps.TvSearchAvailable);
              Assert.True(torznabCaps.MovieSearchAvailable);
              Assert.True(torznabCaps.MusicSearchAvailable);
              Assert.True(torznabCaps.BookSearchAvailable);
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(null); // null search modes
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>()); // empty search modes
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"bad", new List<string> {"q"}} // bad search mode
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"search", new List<string> {"bad"}} // search mode with bad parameters
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
          }
  
          [Test]
          public void TestParseTvSearchParams()
          {
              var torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"tv-search", null}
              });
              Assert.IsEmpty(torznabCaps.MovieSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"tv-search", new List<string>()}
              });
              Assert.IsEmpty(torznabCaps.MovieSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"tv-search", new List<string> {"q", "tvdbid"}}
              });
              Assert.AreEqual(new List<TvSearchParam> { TvSearchParam.Q, TvSearchParam.TvdbId }, torznabCaps.TvSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"search", new List<string>{"q"}},
                      {"tv-search", new List<string> {"q", "q"}} // duplicate param
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"search", new List<string>{"q"}},
                      {"tv-search", new List<string> {"bad"}} // unsupported param
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
          }
  
          [Test]
          public void TestParseMovieSearchParams()
          {
              var torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"movie-search", null}
              });
              Assert.IsEmpty(torznabCaps.MovieSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"movie-search", new List<string>()}
              });
              Assert.IsEmpty(torznabCaps.MovieSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"movie-search", new List<string> {"q", "imdbid"}}
              });
              Assert.AreEqual(new List<MovieSearchParam> { MovieSearchParam.Q, MovieSearchParam.ImdbId }, torznabCaps.MovieSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"search", new List<string>{"q"}},
                      {"movie-search", new List<string> {"q", "q"}} // duplicate param
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"search", new List<string>{"q"}},
                      {"movie-search", new List<string> {"bad"}} // unsupported param
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
          }
  
          [Test]
          public void TestParseMusicSearchParams()
          {
              var torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"music-search", null}
              });
              Assert.IsEmpty(torznabCaps.MovieSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"music-search", new List<string>()}
              });
              Assert.IsEmpty(torznabCaps.MovieSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"music-search", new List<string> {"q", "label"}}
              });
              Assert.AreEqual(new List<MusicSearchParam> { MusicSearchParam.Q, MusicSearchParam.Label }, torznabCaps.MusicSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"search", new List<string>{"q"}},
                      {"music-search", new List<string> {"q", "q"}} // duplicate param
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"search", new List<string>{"q"}},
                      {"music-search", new List<string> {"bad"}} // unsupported param
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
          }
  
          [Test]
          public void TestParseBookSearchParams()
          {
              var torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"book-search", null}
              });
              Assert.IsEmpty(torznabCaps.MovieSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"book-search", new List<string>()}
              });
              Assert.IsEmpty(torznabCaps.MovieSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
              {
                  {"search", new List<string>{"q"}},
                  {"book-search", new List<string> {"q", "title"}}
              });
              Assert.AreEqual(new List<BookSearchParam> { BookSearchParam.Q, BookSearchParam.Title }, torznabCaps.BookSearchParams);
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"search", new List<string>{"q"}},
                      {"book-search", new List<string> {"q", "q"}} // duplicate param
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
  
              torznabCaps = new TorznabCapabilities();
              try
              {
                  torznabCaps.ParseCardigannSearchModes(new Dictionary<string, List<string>>
                  {
                      {"search", new List<string>{"q"}},
                      {"book-search", new List<string> {"bad"}} // unsupported param
                  });
                  Assert.Fail();
              }
              catch (Exception)
              {
                  // ignored
              }
          }
  
          [Test]
          public void TestTorznabCaps()
          {
              // test header
              var torznabCaps = new TorznabCapabilities();
              var xDocument = torznabCaps.GetXDocument();
              Assert.AreEqual("caps", xDocument.Root?.Name.LocalName);
              Assert.AreEqual("Jackett", xDocument.Root?.Element("server")?.Attribute("title")?.Value);
              Assert.True(xDocument.Root?.Element("searching")?.HasElements);
              Assert.False(xDocument.Root?.Element("categories")?.HasElements);
  
              // test all features disabled
              torznabCaps = new TorznabCapabilities
              {
                  SearchAvailable = false
              };
              xDocument = torznabCaps.GetXDocument();
              var xDocumentSearching = xDocument.Root?.Element("searching");
              Assert.AreEqual("no", xDocumentSearching?.Element("search")?.Attribute("available")?.Value);
              Assert.AreEqual("q", xDocumentSearching?.Element("search")?.Attribute("supportedParams")?.Value);
              Assert.AreEqual("no", xDocumentSearching?.Element("tv-search")?.Attribute("available")?.Value);
              Assert.AreEqual("q", xDocumentSearching?.Element("tv-search")?.Attribute("supportedParams")?.Value);
              Assert.AreEqual("no", xDocumentSearching?.Element("movie-search")?.Attribute("available")?.Value);
              Assert.AreEqual("q", xDocumentSearching?.Element("movie-search")?.Attribute("supportedParams")?.Value);
              Assert.AreEqual("no", xDocumentSearching?.Element("music-search")?.Attribute("available")?.Value);
              Assert.AreEqual("q", xDocumentSearching?.Element("music-search")?.Attribute("supportedParams")?.Value);
              Assert.AreEqual("no", xDocumentSearching?.Element("audio-search")?.Attribute("available")?.Value);
              Assert.AreEqual("q", xDocumentSearching?.Element("audio-search")?.Attribute("supportedParams")?.Value);
              Assert.AreEqual("no", xDocumentSearching?.Element("book-search")?.Attribute("available")?.Value);
              Assert.AreEqual("q", xDocumentSearching?.Element("book-search")?.Attribute("supportedParams")?.Value);
  
              // test all features enabled
              torznabCaps = new TorznabCapabilities
              {
                  SearchAvailable = true,
                  TvSearchParams = new List<TvSearchParam>
                  {
                      TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId, TvSearchParam.RId
                  },
                  MovieSearchParams = new List<MovieSearchParam>
                  {
                      MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
                  },
                  MusicSearchParams = new List<MusicSearchParam>
                  {
                      MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year
                  },
                  BookSearchParams = new List<BookSearchParam>
                  {
                      BookSearchParam.Q, BookSearchParam.Title, BookSearchParam.Author
                  },
              };
              xDocument = torznabCaps.GetXDocument();
  
gt:             xDocumentSearching = xDocument.Root?.Element("searching");