From 9384192743de0a4205473afdab6a7df898ad09a6 Mon Sep 17 00:00:00 2001 From: Shavarsh Movsesyan Date: Thu, 9 Nov 2017 16:03:00 +0200 Subject: [PATCH 1/9] Added support for user's manga list. Added support for updating user's anime and manga MAL records. Minor renaming and reordering. Added 'Anime' and 'Manga' for better organization of the 'MalApi' project. --- MalApi.Example/Program.cs | 13 +- .../GetAnimeDetailsTest.cs | 1 + MalApi.NetCoreExample/Program.cs | 4 +- MalApi.UnitTests/AnimeListCacheTests.cs | 1 + MalApi.UnitTests/MalAppInfoXmlTests.cs | 11 +- MalApi.sln | 4 +- .../AnimeCompletionStatus.cs} | 4 +- .../{ => Anime}/MalAnimeInfoFromUserLookup.cs | 6 +- .../{ => Anime}/MalAnimeNotFoundException.cs | 2 +- .../MalAnimeSeriesStatus.cs} | 4 +- MalApi/{ => Anime}/MalAnimeType.cs | 2 +- MalApi/{ => Anime}/MyAnimeListEntry.cs | 6 +- MalApi/Anime/UpdateAnimeObject.cs | 85 ++++++ MalApi/MalApi.csproj | 1 + MalApi/MalAppInfoXml.cs | 114 +++++++- MalApi/MalUserLookupResults.cs | 10 + MalApi/Manga/MalMangaInfoFromUserLookup.cs | 65 +++++ MalApi/Manga/MalMangaSeriesStatus.cs | 9 + MalApi/Manga/MalMangaType.cs | 14 + MalApi/Manga/MangaCompletionStatus.cs | 11 + MalApi/Manga/MyMangaListEntry.cs | 55 ++++ MalApi/Manga/UpdateMangaObject.cs | 90 ++++++ MalApi/MyAnimeListApi.cs | 269 +++++++++++++++++- MalApi/UpdateObjectBase.cs | 41 +++ 24 files changed, 791 insertions(+), 31 deletions(-) rename MalApi/{CompletionStatus.cs => Anime/AnimeCompletionStatus.cs} (92%) rename MalApi/{ => Anime}/MalAnimeInfoFromUserLookup.cs (93%) rename MalApi/{ => Anime}/MalAnimeNotFoundException.cs (97%) rename MalApi/{MalSeriesStatus.cs => Anime/MalAnimeSeriesStatus.cs} (92%) rename MalApi/{ => Anime}/MalAnimeType.cs (97%) rename MalApi/{ => Anime}/MyAnimeListEntry.cs (90%) create mode 100644 MalApi/Anime/UpdateAnimeObject.cs create mode 100644 MalApi/Manga/MalMangaInfoFromUserLookup.cs create mode 100644 MalApi/Manga/MalMangaSeriesStatus.cs create mode 100644 MalApi/Manga/MalMangaType.cs create mode 100644 MalApi/Manga/MangaCompletionStatus.cs create mode 100644 MalApi/Manga/MyMangaListEntry.cs create mode 100644 MalApi/Manga/UpdateMangaObject.cs create mode 100644 MalApi/UpdateObjectBase.cs diff --git a/MalApi.Example/Program.cs b/MalApi.Example/Program.cs index 5ab08fd..b64d141 100644 --- a/MalApi.Example/Program.cs +++ b/MalApi.Example/Program.cs @@ -2,6 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using MalApi.Anime; +using MalApi.Manga; + namespace MalApi.Example { @@ -24,7 +27,15 @@ static void Main(string[] args) api.UserAgent = "MalApiExample"; api.TimeoutInMs = 15000; - MalUserLookupResults userLookup = api.GetAnimeListForUser("LordHighCaptain"); + var animeUpdateInfo = new UpdateAnimeObject(episode: "26", status: "2", score: "9"); + string userLookup2 = api.UpdateAnimeForUser(1, animeUpdateInfo, "user", "pass"); + + var mangaUpdateInfo = new UpdateMangaObject(chapter: "20", volume: "3", score: "8"); + string userLookup3 = api.UpdateMangaForUser(952, mangaUpdateInfo, "user", "pass"); + + + + MalUserLookupResults userLookup = api.GetAnimeListForUser("user"); foreach (MyAnimeListEntry listEntry in userLookup.AnimeList) { Console.WriteLine("Rating for {0}: {1}", listEntry.AnimeInfo.Title, listEntry.Score); diff --git a/MalApi.IntegrationTests/GetAnimeDetailsTest.cs b/MalApi.IntegrationTests/GetAnimeDetailsTest.cs index 223ee2e..42d93dc 100644 --- a/MalApi.IntegrationTests/GetAnimeDetailsTest.cs +++ b/MalApi.IntegrationTests/GetAnimeDetailsTest.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using FluentAssertions; using Xunit; +using MalApi.Anime; namespace MalApi.IntegrationTests { diff --git a/MalApi.NetCoreExample/Program.cs b/MalApi.NetCoreExample/Program.cs index b48ef4e..977a4c0 100644 --- a/MalApi.NetCoreExample/Program.cs +++ b/MalApi.NetCoreExample/Program.cs @@ -1,5 +1,5 @@ -using MalApi; -using System; +using System; +using MalApi.Anime; namespace MalApi.NetCoreExample { diff --git a/MalApi.UnitTests/AnimeListCacheTests.cs b/MalApi.UnitTests/AnimeListCacheTests.cs index bb8c629..1c9dd15 100644 --- a/MalApi.UnitTests/AnimeListCacheTests.cs +++ b/MalApi.UnitTests/AnimeListCacheTests.cs @@ -5,6 +5,7 @@ using MalApi; using System.Threading; using Xunit; +using MalApi.Anime; namespace MalApi.UnitTests { diff --git a/MalApi.UnitTests/MalAppInfoXmlTests.cs b/MalApi.UnitTests/MalAppInfoXmlTests.cs index bad5cd3..4f89fae 100644 --- a/MalApi.UnitTests/MalAppInfoXmlTests.cs +++ b/MalApi.UnitTests/MalAppInfoXmlTests.cs @@ -6,6 +6,7 @@ using System.Xml.Linq; using FluentAssertions; using Xunit; +using MalApi.Anime; namespace MalApi.UnitTests { @@ -25,7 +26,7 @@ public void ParseWithTextReaderTest() public void ParseWithXElementTest() { XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_clean.xml")); - MalUserLookupResults results = MalAppInfoXml.Parse(doc); + MalUserLookupResults results = MalAppInfoXml.ParseAnimeResults(doc); DoAsserts(results); } @@ -42,7 +43,7 @@ public void ParseInvalidUserWithTextReaderTest() public void ParseInvalidUserWithXElementTest() { XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_no_such_user.xml")); - Assert.Throws(() => MalAppInfoXml.Parse(doc)); + Assert.Throws(() => MalAppInfoXml.ParseAnimeResults(doc)); } [Fact] @@ -58,7 +59,7 @@ public void ParseOldInvalidUserWithTextReaderTest() public void ParseOldInvalidUserWithXElementTest() { XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_no_such_user_old.xml")); - Assert.Throws(() => MalAppInfoXml.Parse(doc)); + Assert.Throws(() => MalAppInfoXml.ParseAnimeResults(doc)); } private void DoAsserts(MalUserLookupResults results) @@ -74,7 +75,7 @@ private void DoAsserts(MalUserLookupResults results) Assert.Equal(7, entry.NumEpisodesWatched); Assert.Equal(7, entry.Score); - Assert.Equal(CompletionStatus.Watching, entry.Status); + Assert.Equal(AnimeCompletionStatus.Watching, entry.Status); // Test tags with Equal, not equivalent, because order in tags matters Assert.Equal(new List() { "duck", "goose" }, entry.Tags); @@ -85,7 +86,7 @@ private void DoAsserts(MalUserLookupResults results) entry.AnimeInfo.Synonyms.Should().BeEquivalentTo(new List() { "The Vanishment of Haruhi Suzumiya", "Suzumiya Haruhi no Syoshitsu", "Haruhi movie", "The Disappearance of Haruhi Suzumiya" }); Assert.Equal((decimal?)null, entry.Score); Assert.Equal(0, entry.NumEpisodesWatched); - Assert.Equal(CompletionStatus.PlanToWatch, entry.Status); + Assert.Equal(AnimeCompletionStatus.PlanToWatch, entry.Status); Assert.Equal(new List(), entry.Tags); entry = results.AnimeList.Where(anime => anime.AnimeInfo.AnimeId == 889).First(); diff --git a/MalApi.sln b/MalApi.sln index 080f0ef..88c85b2 100644 --- a/MalApi.sln +++ b/MalApi.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.14 +VisualStudioVersion = 15.0.26430.15 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MalApi", "MalApi\MalApi.csproj", "{85BC477F-4798-4006-A342-715E7565B3BB}" EndProject @@ -18,7 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{00247D .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MalApi.NetCoreExample", "MalApi.NetCoreExample\MalApi.NetCoreExample.csproj", "{EF72FAC1-AE34-4D7B-9839-4ED50288CFB4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MalApi.NetCoreExample", "MalApi.NetCoreExample\MalApi.NetCoreExample.csproj", "{EF72FAC1-AE34-4D7B-9839-4ED50288CFB4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/MalApi/CompletionStatus.cs b/MalApi/Anime/AnimeCompletionStatus.cs similarity index 92% rename from MalApi/CompletionStatus.cs rename to MalApi/Anime/AnimeCompletionStatus.cs index e5754c3..37709bf 100644 --- a/MalApi/CompletionStatus.cs +++ b/MalApi/Anime/AnimeCompletionStatus.cs @@ -3,9 +3,9 @@ using System.Linq; using System.Text; -namespace MalApi +namespace MalApi.Anime { - public enum CompletionStatus + public enum AnimeCompletionStatus { Watching = 1, Completed = 2, diff --git a/MalApi/MalAnimeInfoFromUserLookup.cs b/MalApi/Anime/MalAnimeInfoFromUserLookup.cs similarity index 93% rename from MalApi/MalAnimeInfoFromUserLookup.cs rename to MalApi/Anime/MalAnimeInfoFromUserLookup.cs index eb56bad..09803a8 100644 --- a/MalApi/MalAnimeInfoFromUserLookup.cs +++ b/MalApi/Anime/MalAnimeInfoFromUserLookup.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Text; -namespace MalApi +namespace MalApi.Anime { public class MalAnimeInfoFromUserLookup : IEquatable { @@ -16,7 +16,7 @@ public class MalAnimeInfoFromUserLookup : IEquatable public MalAnimeType Type { get; private set; } public ICollection Synonyms { get; private set; } - public MalSeriesStatus Status { get; private set; } + public MalAnimeSeriesStatus Status { get; private set; } /// /// Could be 0 for anime that hasn't aired yet or less than the planned number of episodes for a series currently airing. @@ -27,7 +27,7 @@ public class MalAnimeInfoFromUserLookup : IEquatable public UncertainDate EndDate { get; private set; } public string ImageUrl { get; private set; } - public MalAnimeInfoFromUserLookup(int animeId, string title, MalAnimeType type, ICollection synonyms, MalSeriesStatus status, + public MalAnimeInfoFromUserLookup(int animeId, string title, MalAnimeType type, ICollection synonyms, MalAnimeSeriesStatus status, int numEpisodes, UncertainDate startDate, UncertainDate endDate, string imageUrl) { AnimeId = animeId; diff --git a/MalApi/MalAnimeNotFoundException.cs b/MalApi/Anime/MalAnimeNotFoundException.cs similarity index 97% rename from MalApi/MalAnimeNotFoundException.cs rename to MalApi/Anime/MalAnimeNotFoundException.cs index 69d712f..6c21405 100644 --- a/MalApi/MalAnimeNotFoundException.cs +++ b/MalApi/Anime/MalAnimeNotFoundException.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Text; -namespace MalApi +namespace MalApi.Anime { /// /// Indicates that the anime that was searched for does not exist. diff --git a/MalApi/MalSeriesStatus.cs b/MalApi/Anime/MalAnimeSeriesStatus.cs similarity index 92% rename from MalApi/MalSeriesStatus.cs rename to MalApi/Anime/MalAnimeSeriesStatus.cs index 8002359..762fb4b 100644 --- a/MalApi/MalSeriesStatus.cs +++ b/MalApi/Anime/MalAnimeSeriesStatus.cs @@ -3,9 +3,9 @@ using System.Linq; using System.Text; -namespace MalApi +namespace MalApi.Anime { - public enum MalSeriesStatus + public enum MalAnimeSeriesStatus { Airing = 1, FinishedAiring = 2, diff --git a/MalApi/MalAnimeType.cs b/MalApi/Anime/MalAnimeType.cs similarity index 97% rename from MalApi/MalAnimeType.cs rename to MalApi/Anime/MalAnimeType.cs index 6fbab88..63d7cd9 100644 --- a/MalApi/MalAnimeType.cs +++ b/MalApi/Anime/MalAnimeType.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Text; -namespace MalApi +namespace MalApi.Anime { public enum MalAnimeType { diff --git a/MalApi/MyAnimeListEntry.cs b/MalApi/Anime/MyAnimeListEntry.cs similarity index 90% rename from MalApi/MyAnimeListEntry.cs rename to MalApi/Anime/MyAnimeListEntry.cs index e4228d1..475f0f4 100644 --- a/MalApi/MyAnimeListEntry.cs +++ b/MalApi/Anime/MyAnimeListEntry.cs @@ -3,12 +3,12 @@ using System.Linq; using System.Text; -namespace MalApi +namespace MalApi.Anime { public class MyAnimeListEntry : IEquatable { public decimal? Score { get; private set; } - public CompletionStatus Status { get; private set; } + public AnimeCompletionStatus Status { get; private set; } public int NumEpisodesWatched { get; private set; } public UncertainDate MyStartDate { get; private set; } public UncertainDate MyFinishDate { get; private set; } @@ -16,7 +16,7 @@ public class MyAnimeListEntry : IEquatable public MalAnimeInfoFromUserLookup AnimeInfo { get; private set; } public ICollection Tags { get; private set; } - public MyAnimeListEntry(decimal? score, CompletionStatus status, int numEpisodesWatched, UncertainDate myStartDate, + public MyAnimeListEntry(decimal? score, AnimeCompletionStatus status, int numEpisodesWatched, UncertainDate myStartDate, UncertainDate myFinishDate, DateTime myLastUpdate, MalAnimeInfoFromUserLookup animeInfo, ICollection tags) { Score = score; diff --git a/MalApi/Anime/UpdateAnimeObject.cs b/MalApi/Anime/UpdateAnimeObject.cs new file mode 100644 index 0000000..6a70c1b --- /dev/null +++ b/MalApi/Anime/UpdateAnimeObject.cs @@ -0,0 +1,85 @@ +using System.Xml.Serialization; + +namespace MalApi.Anime +{ + [XmlRoot("entry")] + public class UpdateAnimeObject : UpdateObjectBase + { + [XmlElement("episode")] + public string Episode { get; set; } = null; + + [XmlElement("status")] + public string Status { get; set; } = null; + + [XmlElement("score")] + public string Score { get; set; } = null; + + [XmlElement("storage_type")] + public string StorageType { get; set; } = null; + + [XmlElement("storage_value")] + public string StorageValue { get; set; } = null; + + [XmlElement("times_rewatched")] + public string TimesRewatched { get; set; } = null; + + [XmlElement("rewatch_value")] + public string RewatchValue { get; set; } = null; + + [XmlElement("date_start")] + public string DateStart { get; set; } = null; + + [XmlElement("date_finish")] + public string DateFinish { get; set; } = null; + + [XmlElement("priority")] + public string Priority { get; set; } = null; + + [XmlElement("enable_discussion")] + public string EnableDiscussion { get; set; } = null; + + [XmlElement("enable_rewatching")] + public string EnableRewatching { get; set; } = null; + + [XmlElement("comments")] + public string Comments { get; set; } = null; + + [XmlElement("tags")] + public string Tags { get; set; } = null; + + private UpdateAnimeObject() + { + } + + public UpdateAnimeObject(string episode = null, + string status = null, + string score = null, + string storageType = null, + string storageValue = null, + string timesRewatched = null, + string rewatchValue = null, + string dateStart = null, + string dateFinish = null, + string priority = null, + string enableDiscussion = null, + string enableRewatching = null, + string comments = null, + string tags = null) + { + Episode = episode; + Status = status; + Score = score; + StorageType = storageType; + StorageValue = storageValue; + TimesRewatched = timesRewatched; + RewatchValue = rewatchValue; + DateStart = dateStart; + DateFinish = dateFinish; + Priority = priority; + EnableDiscussion = enableDiscussion; + EnableRewatching = enableRewatching; + Comments = comments; + Tags = tags; + } + } +} diff --git a/MalApi/MalApi.csproj b/MalApi/MalApi.csproj index 43e369b..072534c 100644 --- a/MalApi/MalApi.csproj +++ b/MalApi/MalApi.csproj @@ -43,5 +43,6 @@ + \ No newline at end of file diff --git a/MalApi/MalAppInfoXml.cs b/MalApi/MalAppInfoXml.cs index 71d055c..d19d0b6 100644 --- a/MalApi/MalAppInfoXml.cs +++ b/MalApi/MalAppInfoXml.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.IO; using System.Xml.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Threading; +using MalApi.Anime; +using MalApi.Manga; namespace MalApi { @@ -31,7 +32,16 @@ public static async Task ParseAsync(TextReader xmlTextRead // No async version of XDocument.Load in the full framework yet. // StringReader won't block though. XDocument doc = XDocument.Load(sanitizedXmlTextReader); - return Parse(doc); + + IEnumerable anime = doc.Root.Elements("anime").ToList(); + if(anime.Count() != 0) + { + return ParseAnimeResults(doc); + } + else + { + return ParseMangaResults(doc); + } } } @@ -104,7 +114,7 @@ private static async Task SanitizeAnimeListXmlAsync(TextReader xml /// /// /// - public static MalUserLookupResults Parse(XDocument doc) + public static MalUserLookupResults ParseAnimeResults(XDocument doc) { Logging.Log.Trace("Parsing XML."); @@ -147,7 +157,7 @@ public static MalUserLookupResults Parse(XDocument doc) int numEpisodes = GetElementValueInt(anime, "series_episodes"); int seriesStatusInt = GetElementValueInt(anime, "series_status"); - MalSeriesStatus seriesStatus = (MalSeriesStatus)seriesStatusInt; + MalAnimeSeriesStatus seriesStatus = (MalAnimeSeriesStatus)seriesStatusInt; string seriesStartString = GetElementValueString(anime, "series_start"); UncertainDate seriesStart = UncertainDate.FromMalDateString(seriesStartString); @@ -174,7 +184,7 @@ public static MalUserLookupResults Parse(XDocument doc) decimal? myScore = rawScore == 0 ? (decimal?)null : rawScore; int completionStatusInt = GetElementValueInt(anime, "my_status"); - CompletionStatus completionStatus = (CompletionStatus)completionStatusInt; + AnimeCompletionStatus completionStatus = (AnimeCompletionStatus)completionStatusInt; long lastUpdatedUnixTimestamp = GetElementValueLong(anime, "my_last_updated"); DateTime lastUpdated = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + TimeSpan.FromSeconds(lastUpdatedUnixTimestamp); @@ -194,6 +204,100 @@ public static MalUserLookupResults Parse(XDocument doc) return results; } + public static MalUserLookupResults ParseMangaResults(XDocument doc) + { + Logging.Log.Trace("Parsing XML."); + + XElement error = doc.Root.Element("error"); + if (error != null && (string)error == "Invalid username") + { + throw new MalUserNotFoundException("No MAL list exists for this user."); + } + else if (error != null) + { + throw new MalApiException((string)error); + } + + if (!doc.Root.HasElements) + { + throw new MalUserNotFoundException("No MAL list exists for this user."); + } + + XElement myinfo = GetExpectedElement(doc.Root, "myinfo"); + int userId = GetElementValueInt(myinfo, "user_id"); + string canonicalUserName = GetElementValueString(myinfo, "user_name"); + + List entries = new List(); + + IEnumerable mangas = doc.Root.Elements("manga"); + foreach (XElement manga in mangas) + { + int mangaId = GetElementValueInt(manga, "series_mangadb_id"); + string title = GetElementValueString(manga, "series_title"); + + string synonymList = GetElementValueString(manga, "series_synonyms"); + string[] rawSynonyms = synonymList.Split(SynonymSeparator, StringSplitOptions.RemoveEmptyEntries); + + // filter out synonyms that are the same as the main title + HashSet synonyms = new HashSet(rawSynonyms.Where(synonym => !synonym.Equals(title, StringComparison.Ordinal))); + + int seriesTypeInt = GetElementValueInt(manga, "series_type"); + MalMangaType seriesType = (MalMangaType)seriesTypeInt; + + int numChapters = GetElementValueInt(manga, "series_chapters"); + + int numVolumes = GetElementValueInt(manga, "series_volumes"); + + int seriesStatusInt = GetElementValueInt(manga, "series_status"); + MalMangaSeriesStatus seriesStatus = (MalMangaSeriesStatus)seriesStatusInt; + + string seriesStartString = GetElementValueString(manga, "series_start"); + UncertainDate seriesStart = UncertainDate.FromMalDateString(seriesStartString); + + string seriesEndString = GetElementValueString(manga, "series_end"); + UncertainDate seriesEnd = UncertainDate.FromMalDateString(seriesEndString); + + string seriesImage = GetElementValueString(manga, "series_image"); + + MalMangaInfoFromUserLookup mangaInfo = new MalMangaInfoFromUserLookup(mangaId: mangaId, title: title, + type: seriesType, synonyms: synonyms, status: seriesStatus, numChapters: numChapters, numVolumes: numVolumes, startDate: seriesStart, + endDate: seriesEnd, imageUrl: seriesImage); + + + int numChaptersRead = GetElementValueInt(manga, "my_read_chapters"); + + int numVolumesRead = GetElementValueInt(manga, "my_read_volumes"); + + string myStartDateString = GetElementValueString(manga, "my_start_date"); + UncertainDate myStartDate = UncertainDate.FromMalDateString(myStartDateString); + + string myFinishDateString = GetElementValueString(manga, "my_finish_date"); + UncertainDate myFinishDate = UncertainDate.FromMalDateString(myFinishDateString); + + decimal rawScore = GetElementValueDecimal(manga, "my_score"); + decimal? myScore = rawScore == 0 ? (decimal?)null : rawScore; + + int completionStatusInt = GetElementValueInt(manga, "my_status"); + MangaCompletionStatus completionStatus = (MangaCompletionStatus)completionStatusInt; + + long lastUpdatedUnixTimestamp = GetElementValueLong(manga, "my_last_updated"); + DateTime lastUpdated = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + TimeSpan.FromSeconds(lastUpdatedUnixTimestamp); + + string rawTagsString = GetElementValueString(manga, "my_tags"); + string[] untrimmedTags = rawTagsString.Split(TagSeparator, StringSplitOptions.RemoveEmptyEntries); + List tags = new List(untrimmedTags.Select(tag => tag.Trim())); + + MyMangaListEntry entry = new MyMangaListEntry(score: myScore, status: completionStatus, numChaptersRead: numChaptersRead, numVolumesRead: numVolumesRead, + myStartDate: myStartDate, myFinishDate: myFinishDate, myLastUpdate: lastUpdated, mangaInfo: mangaInfo, tags: tags); + + entries.Add(entry); + } + + MalUserLookupResults results = new MalUserLookupResults(userId: userId, canonicalUserName: canonicalUserName, mangaList: entries); + Logging.Log.Trace("Parsed XML."); + return results; + } + private static readonly string[] SynonymSeparator = new string[] { "; " }; private static readonly char[] TagSeparator = new char[] { ',' }; diff --git a/MalApi/MalUserLookupResults.cs b/MalApi/MalUserLookupResults.cs index 0edc1ce..19e1ec5 100644 --- a/MalApi/MalUserLookupResults.cs +++ b/MalApi/MalUserLookupResults.cs @@ -2,12 +2,15 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using MalApi.Anime; +using MalApi.Manga; namespace MalApi { public class MalUserLookupResults { public ICollection AnimeList { get; private set; } + public ICollection MangaList { get; private set; } public int UserId { get; private set; } /// @@ -21,6 +24,13 @@ public MalUserLookupResults(int userId, string canonicalUserName, ICollection mangaList) + { + UserId = userId; + CanonicalUserName = canonicalUserName; + MangaList = mangaList; + } } } diff --git a/MalApi/Manga/MalMangaInfoFromUserLookup.cs b/MalApi/Manga/MalMangaInfoFromUserLookup.cs new file mode 100644 index 0000000..dfa6d66 --- /dev/null +++ b/MalApi/Manga/MalMangaInfoFromUserLookup.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MalApi.Manga +{ + public class MalMangaInfoFromUserLookup : IEquatable + { + public int MangaId { get; private set; } + public string Title { get; private set; } + + /// + /// Could be something other than the enumerated values if MAL adds new types! + /// + public MalMangaType Type { get; private set; } + + public ICollection Synonyms { get; private set; } + public MalMangaSeriesStatus Status { get; private set; } + + public int NumChapters { get; private set; } + + public int NumVolumes { get; private set; } + + public UncertainDate StartDate { get; private set; } + public UncertainDate EndDate { get; private set; } + public string ImageUrl { get; private set; } + + public MalMangaInfoFromUserLookup(int mangaId, string title, MalMangaType type, ICollection synonyms, MalMangaSeriesStatus status, + int numChapters, int numVolumes, UncertainDate startDate, UncertainDate endDate, string imageUrl) + { + MangaId = mangaId; + Title = title; + Type = type; + Synonyms = synonyms; + Status = status; + NumChapters = numChapters; + NumVolumes = numVolumes; + StartDate = startDate; + EndDate = endDate; + ImageUrl = imageUrl; + } + + public override bool Equals(object obj) + { + return Equals(obj as MalMangaInfoFromUserLookup); + } + + public bool Equals(MalMangaInfoFromUserLookup other) + { + if (other == null) return false; + return this.MangaId == other.MangaId; + } + + public override int GetHashCode() + { + return MangaId.GetHashCode(); + } + + public override string ToString() + { + return Title; + } + } +} diff --git a/MalApi/Manga/MalMangaSeriesStatus.cs b/MalApi/Manga/MalMangaSeriesStatus.cs new file mode 100644 index 0000000..a9b0943 --- /dev/null +++ b/MalApi/Manga/MalMangaSeriesStatus.cs @@ -0,0 +1,9 @@ +namespace MalApi.Manga +{ + public enum MalMangaSeriesStatus + { + Publishing = 1, + Finished = 2, + NotYetPublished = 3 + } +} \ No newline at end of file diff --git a/MalApi/Manga/MalMangaType.cs b/MalApi/Manga/MalMangaType.cs new file mode 100644 index 0000000..86f935c --- /dev/null +++ b/MalApi/Manga/MalMangaType.cs @@ -0,0 +1,14 @@ +namespace MalApi.Manga +{ + public enum MalMangaType + { + Unknown = 0, + Manga = 1, + Novel = 2, + OneShot = 3, + Doujin = 4, // not sure + Manwha = 5, + Manhua = 6, + OEL = 7 // not sure + } +} \ No newline at end of file diff --git a/MalApi/Manga/MangaCompletionStatus.cs b/MalApi/Manga/MangaCompletionStatus.cs new file mode 100644 index 0000000..6960e69 --- /dev/null +++ b/MalApi/Manga/MangaCompletionStatus.cs @@ -0,0 +1,11 @@ +namespace MalApi.Manga +{ + public enum MangaCompletionStatus + { + Reading = 1, + Completed = 2, + OnHold = 3, + Dropped = 4, + PlanToRead = 6, + } +} \ No newline at end of file diff --git a/MalApi/Manga/MyMangaListEntry.cs b/MalApi/Manga/MyMangaListEntry.cs new file mode 100644 index 0000000..7c3ca8c --- /dev/null +++ b/MalApi/Manga/MyMangaListEntry.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MalApi.Manga +{ + public class MyMangaListEntry : IEquatable + { + public decimal? Score { get; private set; } + public MangaCompletionStatus Status { get; private set; } + public int NumChaptersRead { get; private set; } + public int NumVolumesRead { get; private set; } + public UncertainDate MyStartDate { get; private set; } + public UncertainDate MyFinishDate { get; private set; } + public DateTime MyLastUpdate { get; private set; } + public MalMangaInfoFromUserLookup MangaInfo { get; private set; } + public ICollection Tags { get; private set; } + + public MyMangaListEntry(decimal? score, MangaCompletionStatus status, int numChaptersRead, int numVolumesRead, UncertainDate myStartDate, + UncertainDate myFinishDate, DateTime myLastUpdate, MalMangaInfoFromUserLookup mangaInfo, ICollection tags) + { + Score = score; + Status = status; + NumChaptersRead = numChaptersRead; + NumVolumesRead = numVolumesRead; + MyStartDate = myStartDate; + MyFinishDate = myFinishDate; + MyLastUpdate = myLastUpdate; + MangaInfo = mangaInfo; + Tags = tags; + } + + public bool Equals(MyMangaListEntry other) + { + if (other == null) return false; + return this.MangaInfo.MangaId == other.MangaInfo.MangaId; + } + + public override bool Equals(object obj) + { + return Equals(obj as MyMangaListEntry); + } + + public override int GetHashCode() + { + return MangaInfo.MangaId.GetHashCode(); + } + + public override string ToString() + { + return MangaInfo.Title; + } + } +} diff --git a/MalApi/Manga/UpdateMangaObject.cs b/MalApi/Manga/UpdateMangaObject.cs new file mode 100644 index 0000000..2957de6 --- /dev/null +++ b/MalApi/Manga/UpdateMangaObject.cs @@ -0,0 +1,90 @@ +using System.Xml.Serialization; + +namespace MalApi.Manga +{ + [XmlRoot("entry")] + public class UpdateMangaObject : UpdateObjectBase + { + [XmlElement("chapter")] + public string Chapter { get; set; } = null; + + [XmlElement("volume")] + public string Volume { get; set; } = null; + + [XmlElement("status")] + public string Status { get; set; } = null; + + [XmlElement("score")] + public string Score { get; set; } = null; + + [XmlElement("times_reread")] + public string TimesReread { get; set; } = null; + + [XmlElement("reread_value")] + public string RereadValue { get; set; } = null; + + [XmlElement("date_start")] + public string DateStart { get; set; } = null; + + [XmlElement("date_finish")] + public string DateFinish { get; set; } = null; + + [XmlElement("priority")] + public string Priority { get; set; } = null; + + [XmlElement("enable_discussion")] + public string EnableDiscussion { get; set; } = null; + + [XmlElement("enable_rereading")] + public string EnableRereading { get; set; } = null; + + [XmlElement("comments")] + public string Comments { get; set; } = null; + + [XmlElement("scan_group")] + public string ScanGroup { get; set; } = null; + + [XmlElement("tags")] + public string Tags { get; set; } = null; + + [XmlElement("retail_volumes")] + public string RetailVolumes { get; set; } = null; + + public UpdateMangaObject() + { + } + + public UpdateMangaObject(string chapter = null, + string volume = null, + string status = null, + string score = null, + string timesReread = null, + string rereadValue = null, + string dateStart = null, + string dateFinish = null, + string priority = null, + string enableDiscussion = null, + string enableRereading = null, + string comments = null, + string scanGroup = null, + string tags = null, + string retailVolumes = null) + { + Chapter = chapter; + Volume = volume; + Status = status; + Score = score; + TimesReread = timesReread; + RereadValue = rereadValue; + DateStart = dateStart; + DateFinish = dateFinish; + Priority = priority; + EnableDiscussion = enableDiscussion; + EnableRereading = enableRereading; + Comments = comments; + ScanGroup = scanGroup; + Tags = tags; + RetailVolumes = retailVolumes; + } + } +} diff --git a/MalApi/MyAnimeListApi.cs b/MalApi/MyAnimeListApi.cs index f257f97..2aeccef 100644 --- a/MalApi/MyAnimeListApi.cs +++ b/MalApi/MyAnimeListApi.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Net; using System.IO; @@ -8,6 +7,8 @@ using System.Net.Http; using System.Threading.Tasks; using System.Threading; +using MalApi.Anime; +using MalApi.Manga; namespace MalApi { @@ -16,7 +17,14 @@ namespace MalApi /// public class MyAnimeListApi : IMyAnimeListApi { - private const string MalAppInfoUri = "https://myanimelist.net/malappinfo.php?status=all&type=anime"; + private static readonly string AnimeDetailsUrlFormat = "https://myanimelist.net/anime/{0}"; + + private const string MalAppAnimeInfoUri = "https://myanimelist.net/malappinfo.php?status=all&type=anime&u={0}"; + private const string MalAppMangaInfoUri = "https://myanimelist.net/malappinfo.php?status=all&type=manga&u={0}"; + + private const string MalAppAnimeUpdateUri = "https://myanimelist.net/api/animelist/update/{0}.xml"; + private const string MalAppMangaUpdateUri = "https://myanimelist.net/api/mangalist/update/{0}.xml"; + private const string RecentOnlineUsersUri = "https://myanimelist.net/users.php"; /// @@ -72,6 +80,40 @@ private HttpRequestMessage InitNewRequest(string uri, HttpMethod method) return request; } + private HttpRequestMessage InitNewRequestWithCredentials(string user, string password, string uri, HttpMethod method, UpdateObjectBase updateInfo = null) + { + HttpRequestMessage request = new HttpRequestMessage(method, uri); + + // Requests with credentials require them to be encoded in base64 + string credentials; + if (user != null && password != null) + { + var plainTextBytes = Encoding.UTF8.GetBytes(user + ":" + password); + credentials = Convert.ToBase64String(plainTextBytes); + } + else + { + throw new Exception("Invalid input credentials format (both username and password have to be input OR just the base64 representation"); + } + + if (UserAgent != null) + { + request.Headers.TryAddWithoutValidation("User-Agent", UserAgent); + // Adding the authorization header with the credentials + request.Headers.TryAddWithoutValidation("Authorization", "Basic " + credentials); + } + + // Encoding and adding the new information in the content(body) of the request + if(updateInfo != null) + { + var xml = updateInfo.GenerateXml(); + var content = "data=" + WebUtility.UrlEncode(xml); + request.Content = new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded"); + } + + return request; + } + private Task ProcessRequestAsync(HttpRequestMessage request, Func processingFunc, string baseErrorMessage, CancellationToken cancellationToken) { return ProcessRequestAsync(request, (string html, object dummy) => processingFunc(html), (object)null, @@ -181,6 +223,44 @@ public Task GetAnimeListForUserAsync(string user) return GetAnimeListForUserAsync(user, CancellationToken.None); } + /// + /// Updates a user's anime list entry. + /// + /// ID of the anime + /// The updated information + /// + /// + /// + public Task UpdateAnimeForUserAsync(int animeId, UpdateAnimeObject updateInfo, string user, string password) + { + return UpdateAnimeForUserAsync(animeId, updateInfo, user, password, CancellationToken.None); + } + + /// + /// Gets a user's manga list. This method requires a MAL API key. + /// + /// + /// + /// + /// + public Task GetMangaListForUserAsync(string user) + { + return GetMangaListForUserAsync(user, CancellationToken.None); + } + + /// + /// Updates a user's manga list entry. + /// + /// ID of the manga + /// The updated information + /// + /// + /// + public Task UpdateMangaForUserAsync(int mangaId, UpdateMangaObject updateInfo, string user, string password) + { + return UpdateMangaForUserAsync(mangaId, updateInfo, user, password, CancellationToken.None); + } + /// /// Gets a user's anime list. This method requires a MAL API key. /// @@ -191,7 +271,7 @@ public Task GetAnimeListForUserAsync(string user) /// public async Task GetAnimeListForUserAsync(string user, CancellationToken cancellationToken) { - string userInfoUri = MalAppInfoUri + "&u=" + Uri.EscapeDataString(user); + string userInfoUri = string.Format(MalAppAnimeInfoUri, Uri.EscapeDataString(user)); Logging.Log.InfoFormat("Getting anime list for MAL user {0} using URI {1}", user, userInfoUri); @@ -226,6 +306,147 @@ public async Task GetAnimeListForUserAsync(string user, Ca } } + /// + /// Updates a user's anime list entry. + /// + /// ID of the anime + /// The updated information + /// + /// MAL user + /// MAL password + /// + public async Task UpdateAnimeForUserAsync(int animeId, UpdateAnimeObject updateInfo, string user, string password, CancellationToken cancellationToken) + { + string userInfoUri = string.Format(MalAppAnimeUpdateUri, Uri.EscapeDataString(animeId.ToString())); + + Logging.Log.InfoFormat("Updating anime entry for MAL anime ID {0}, user {1} using URI {2}", animeId, user, userInfoUri); + + Func responseProcessingFunc = (response) => + { + using (TextReader xmlTextReader = new StringReader(response)) + { + try + { + return xmlTextReader.ToString(); + } + catch (Exception ex) + { + throw new Exception(string.Format("Exception for user {0} and anime ID {1}.", user, animeId), ex); + } + } + }; + + try + { + HttpRequestMessage request = InitNewRequestWithCredentials(user, password, userInfoUri, HttpMethod.Post, updateInfo); + + string result = await ProcessRequestAsync(request, responseProcessingFunc, cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed updating anime entry for anime ID {0}, user {0} using url {1}", animeId, user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); + + Logging.Log.InfoFormat("Successfully updated anime entry for anime ID {0} and user {0}", animeId, user); + + return null; + } + catch (OperationCanceledException) + { + Logging.Log.InfoFormat("Canceled updating anime entry for MAL anime ID {0} and user {0}", animeId, user); + throw; + } + } + + /// + /// Gets a user's manga list. This method requires a MAL API key. + /// + /// + /// + /// + /// + /// + public async Task GetMangaListForUserAsync(string user, CancellationToken cancellationToken) + { + string userInfoUri = string.Format(MalAppMangaInfoUri, Uri.EscapeDataString(user)); + + Logging.Log.InfoFormat("Getting manga list for MAL user {0} using URI {1}", user, userInfoUri); + + Func responseProcessingFunc = (xml) => + { + using (TextReader xmlTextReader = new StringReader(xml)) + { + try + { + return MalAppInfoXml.Parse(xmlTextReader); + } + catch (MalUserNotFoundException ex) + { + throw new MalUserNotFoundException(string.Format("No MAL list exists for {0}.", user), ex); + } + } + }; + + try + { + HttpRequestMessage request = InitNewRequest(userInfoUri, HttpMethod.Get); + MalUserLookupResults parsedList = await ProcessRequestAsync(request, responseProcessingFunc, cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed getting manga list for user {0} using url {1}", user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); + + Logging.Log.InfoFormat("Successfully retrieved manga list for user {0}", user); + return parsedList; + } + catch (OperationCanceledException) + { + Logging.Log.InfoFormat("Canceled getting manga list for MAL user {0}", user); + throw; + } + } + + /// + /// Updates a user's manga list entry. + /// + /// ID of the manga + /// The updated information + /// + /// MAL user + /// MAL password + /// + public async Task UpdateMangaForUserAsync(int mangaId, UpdateMangaObject updateInfo, string user, string password, CancellationToken cancellationToken) + { + string userInfoUri = string.Format(MalAppMangaUpdateUri, Uri.EscapeDataString(mangaId.ToString())); + + Logging.Log.InfoFormat("Updating manga entry for MAL manga ID {0}, user {1} using URI {2}", mangaId, user, userInfoUri); + + Func responseProcessingFunc = (response) => + { + using (TextReader xmlTextReader = new StringReader(response)) + { + try + { + return xmlTextReader.ToString(); + } + catch (Exception ex) + { + throw new Exception(string.Format("Exception for user {0} and manga ID {1}.", user, mangaId), ex); + } + } + }; + + try + { + HttpRequestMessage request = InitNewRequestWithCredentials(user, password, userInfoUri, HttpMethod.Post, updateInfo); + + string result = await ProcessRequestAsync(request, responseProcessingFunc, cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed updating manga entry for manga ID {0}, user {0} using url {1}", mangaId, user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); + + Logging.Log.InfoFormat("Successfully updated manga entry for manga ID {0} and user {0}", mangaId, user); + + return null; + } + catch (OperationCanceledException) + { + Logging.Log.InfoFormat("Canceled updating manga entry for MAL manga ID {0} and user {0}", mangaId, user); + throw; + } + } + /// /// Gets a user's anime list. This method requires a MAL API key. /// @@ -238,6 +459,46 @@ public MalUserLookupResults GetAnimeListForUser(string user) return GetAnimeListForUserAsync(user).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); } + /// + /// Updates a user's anime entry. Required username and password or a base64 encrypted username and password. + /// + /// ID of the updated anime + /// Required data to update the anime + /// Username + /// Password + /// base64 encrypted username and password + /// + public string UpdateAnimeForUser(int animeId, UpdateAnimeObject updateInfo, string user, string password) + { + return UpdateAnimeForUserAsync(animeId, updateInfo, user, password).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); + } + + /// + /// Gets a user's manga list. This method requires a MAL API key. + /// + /// + /// + /// + /// + public MalUserLookupResults GetMangaListForUser(string user) + { + return GetMangaListForUserAsync(user).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); + } + + /// + /// Updates a user's manga entry. Required username and password or a base64 encrypted username and password. + /// + /// ID of the updated manga + /// Required data to update the manga + /// Username + /// Password + /// base64 encrypted username and password + /// + public string UpdateMangaForUser(int mangaId, UpdateMangaObject updateInfo, string user, string password) + { + return UpdateMangaForUserAsync(mangaId, updateInfo, user, password).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); + } + private static Lazy s_recentOnlineUsersRegex = new Lazy(() => new Regex("/profile/(?[^\"]+)\">\\k", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)); @@ -306,7 +567,7 @@ private RecentUsersResults ScrapeUsersFromHtml(string recentUsersHtml) return new RecentUsersResults(users); } - private static readonly string AnimeDetailsUrlFormat = "https://myanimelist.net/anime/{0}"; + private static Lazy s_animeDetailsRegex = new Lazy(() => new Regex( @"Genres:\s*?(?:\d+)/[^""]+?""[^>]*?>(?.*?)(?:, )?)*", RegexOptions.Compiled)); diff --git a/MalApi/UpdateObjectBase.cs b/MalApi/UpdateObjectBase.cs new file mode 100644 index 0000000..c49c386 --- /dev/null +++ b/MalApi/UpdateObjectBase.cs @@ -0,0 +1,41 @@ +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace MalApi +{ + public class UpdateObjectBase + { + /// + /// Generates an XML with the current information stored in the object. XML can later be used to update records on MAL. + /// + /// + public string GenerateXml() + { + var emptyNamespace = new XmlSerializerNamespaces(); + emptyNamespace.Add("", ""); + + XmlSerializer xmlSerializer = new XmlSerializer(this.GetType()); + var xml = string.Empty; + + using (var strWriter = new Utf8StringWriter()) + { + using (XmlWriter xmlWriter = XmlWriter.Create(strWriter)) + { + xmlSerializer.Serialize(xmlWriter, this, emptyNamespace); + xml = strWriter.ToString(); + return xml; + } + } + } + + /// + /// Used to override the encoding of the writer to UTF-8. + /// + private class Utf8StringWriter : StringWriter + { + public override Encoding Encoding => Encoding.UTF8; + } + } +} From d597505afdade6e88d5a49d92c2549fb546a0829 Mon Sep 17 00:00:00 2001 From: Shavarsh Movsesyan Date: Sat, 11 Nov 2017 09:18:18 +0200 Subject: [PATCH 2/9] Reverted the namespace change but still kept the folders. Removed unused using statements. --- .gitignore | 3 ++- MalApi.Example/Program.cs | 5 ----- MalApi.IntegrationTests/GetAnimeDetailsTest.cs | 6 +----- MalApi.IntegrationTests/GetAnimeListForUserTest.cs | 7 +------ MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs | 6 +----- MalApi.NetCoreExample/Program.cs | 1 - MalApi.UnitTests/AnimeListCacheTests.cs | 5 ----- MalApi.UnitTests/Helpers.cs | 6 +----- MalApi.UnitTests/MalAppInfoXmlTests.cs | 2 -- MalApi.UnitTests/MyAnimeListApiTests.cs | 6 +----- MalApi/Anime/AnimeCompletionStatus.cs | 7 +------ MalApi/Anime/MalAnimeInfoFromUserLookup.cs | 4 +--- MalApi/Anime/MalAnimeNotFoundException.cs | 5 +---- MalApi/Anime/MalAnimeSeriesStatus.cs | 7 +------ MalApi/Anime/MalAnimeType.cs | 7 +------ MalApi/Anime/MyAnimeListEntry.cs | 4 +--- MalApi/Anime/UpdateAnimeObject.cs | 2 +- MalApi/AnimeDetailsResults.cs | 5 +---- MalApi/AnimeListCache.cs | 2 -- MalApi/CachingMyAnimeListApi.cs | 3 --- MalApi/Genre.cs | 3 --- MalApi/IMyAnimeListApi.cs | 3 --- MalApi/Logging.cs | 7 +------ MalApi/MalApiException.cs | 3 --- MalApi/MalApiRequestException.cs | 3 --- MalApi/MalAppInfoXml.cs | 2 -- MalApi/MalUserLookupResults.cs | 7 +------ MalApi/MalUserNotFoundException.cs | 3 --- MalApi/Manga/MalMangaInfoFromUserLookup.cs | 4 +--- MalApi/Manga/MalMangaSeriesStatus.cs | 2 +- MalApi/Manga/MalMangaType.cs | 2 +- MalApi/Manga/MangaCompletionStatus.cs | 2 +- MalApi/Manga/MyMangaListEntry.cs | 4 +--- MalApi/Manga/UpdateMangaObject.cs | 2 +- MalApi/MyAnimeListApi.cs | 2 -- MalApi/RateLimitingMyAnimeListApi.cs | 3 --- MalApi/RecentUsersResults.cs | 5 +---- MalApi/RetryOnFailureMyAnimeListApi.cs | 3 --- MalApi/UncertainDate.cs | 3 --- 39 files changed, 24 insertions(+), 132 deletions(-) diff --git a/.gitignore b/.gitignore index f3df4a2..72f6958 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ obj/ *.suo *.pubxml packages/*/ -MalApi/package/ \ No newline at end of file +MalApi/package/ +.vs/ diff --git a/MalApi.Example/Program.cs b/MalApi.Example/Program.cs index b64d141..c450d13 100644 --- a/MalApi.Example/Program.cs +++ b/MalApi.Example/Program.cs @@ -1,9 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using MalApi.Anime; -using MalApi.Manga; namespace MalApi.Example diff --git a/MalApi.IntegrationTests/GetAnimeDetailsTest.cs b/MalApi.IntegrationTests/GetAnimeDetailsTest.cs index 42d93dc..0a3e4d6 100644 --- a/MalApi.IntegrationTests/GetAnimeDetailsTest.cs +++ b/MalApi.IntegrationTests/GetAnimeDetailsTest.cs @@ -1,12 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using FluentAssertions; using Xunit; -using MalApi.Anime; namespace MalApi.IntegrationTests { diff --git a/MalApi.IntegrationTests/GetAnimeListForUserTest.cs b/MalApi.IntegrationTests/GetAnimeListForUserTest.cs index 615d953..0cad446 100644 --- a/MalApi.IntegrationTests/GetAnimeListForUserTest.cs +++ b/MalApi.IntegrationTests/GetAnimeListForUserTest.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using MalApi; -using System.Threading.Tasks; +using System.Threading.Tasks; using Xunit; using System.Threading; diff --git a/MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs b/MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs index 6bb881a..6b24b23 100644 --- a/MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs +++ b/MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Xunit; diff --git a/MalApi.NetCoreExample/Program.cs b/MalApi.NetCoreExample/Program.cs index 977a4c0..a1691e6 100644 --- a/MalApi.NetCoreExample/Program.cs +++ b/MalApi.NetCoreExample/Program.cs @@ -1,5 +1,4 @@ using System; -using MalApi.Anime; namespace MalApi.NetCoreExample { diff --git a/MalApi.UnitTests/AnimeListCacheTests.cs b/MalApi.UnitTests/AnimeListCacheTests.cs index 1c9dd15..972d52b 100644 --- a/MalApi.UnitTests/AnimeListCacheTests.cs +++ b/MalApi.UnitTests/AnimeListCacheTests.cs @@ -1,11 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using MalApi; -using System.Threading; using Xunit; -using MalApi.Anime; namespace MalApi.UnitTests { diff --git a/MalApi.UnitTests/Helpers.cs b/MalApi.UnitTests/Helpers.cs index 4b686b5..08e1337 100644 --- a/MalApi.UnitTests/Helpers.cs +++ b/MalApi.UnitTests/Helpers.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; +using System.IO; using System.Reflection; using System.Text; -using System.Threading.Tasks; namespace MalApi.UnitTests { diff --git a/MalApi.UnitTests/MalAppInfoXmlTests.cs b/MalApi.UnitTests/MalAppInfoXmlTests.cs index 4f89fae..4bcea0f 100644 --- a/MalApi.UnitTests/MalAppInfoXmlTests.cs +++ b/MalApi.UnitTests/MalAppInfoXmlTests.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.IO; using System.Xml.Linq; using FluentAssertions; using Xunit; -using MalApi.Anime; namespace MalApi.UnitTests { diff --git a/MalApi.UnitTests/MyAnimeListApiTests.cs b/MalApi.UnitTests/MyAnimeListApiTests.cs index efb50ba..a78412e 100644 --- a/MalApi.UnitTests/MyAnimeListApiTests.cs +++ b/MalApi.UnitTests/MyAnimeListApiTests.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; +using System.Collections.Generic; using System.IO; using FluentAssertions; using Xunit; diff --git a/MalApi/Anime/AnimeCompletionStatus.cs b/MalApi/Anime/AnimeCompletionStatus.cs index 37709bf..6b4d000 100644 --- a/MalApi/Anime/AnimeCompletionStatus.cs +++ b/MalApi/Anime/AnimeCompletionStatus.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace MalApi.Anime +namespace MalApi { public enum AnimeCompletionStatus { diff --git a/MalApi/Anime/MalAnimeInfoFromUserLookup.cs b/MalApi/Anime/MalAnimeInfoFromUserLookup.cs index 09803a8..e1acec4 100644 --- a/MalApi/Anime/MalAnimeInfoFromUserLookup.cs +++ b/MalApi/Anime/MalAnimeInfoFromUserLookup.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace MalApi.Anime +namespace MalApi { public class MalAnimeInfoFromUserLookup : IEquatable { diff --git a/MalApi/Anime/MalAnimeNotFoundException.cs b/MalApi/Anime/MalAnimeNotFoundException.cs index 6c21405..b76a065 100644 --- a/MalApi/Anime/MalAnimeNotFoundException.cs +++ b/MalApi/Anime/MalAnimeNotFoundException.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace MalApi.Anime +namespace MalApi { /// /// Indicates that the anime that was searched for does not exist. diff --git a/MalApi/Anime/MalAnimeSeriesStatus.cs b/MalApi/Anime/MalAnimeSeriesStatus.cs index 762fb4b..ce5607e 100644 --- a/MalApi/Anime/MalAnimeSeriesStatus.cs +++ b/MalApi/Anime/MalAnimeSeriesStatus.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace MalApi.Anime +namespace MalApi { public enum MalAnimeSeriesStatus { diff --git a/MalApi/Anime/MalAnimeType.cs b/MalApi/Anime/MalAnimeType.cs index 63d7cd9..9205bea 100644 --- a/MalApi/Anime/MalAnimeType.cs +++ b/MalApi/Anime/MalAnimeType.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace MalApi.Anime +namespace MalApi { public enum MalAnimeType { diff --git a/MalApi/Anime/MyAnimeListEntry.cs b/MalApi/Anime/MyAnimeListEntry.cs index 475f0f4..e67af66 100644 --- a/MalApi/Anime/MyAnimeListEntry.cs +++ b/MalApi/Anime/MyAnimeListEntry.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace MalApi.Anime +namespace MalApi { public class MyAnimeListEntry : IEquatable { diff --git a/MalApi/Anime/UpdateAnimeObject.cs b/MalApi/Anime/UpdateAnimeObject.cs index 6a70c1b..1b8e090 100644 --- a/MalApi/Anime/UpdateAnimeObject.cs +++ b/MalApi/Anime/UpdateAnimeObject.cs @@ -1,6 +1,6 @@ using System.Xml.Serialization; -namespace MalApi.Anime +namespace MalApi { [XmlRoot("entry")] public class UpdateAnimeObject : UpdateObjectBase diff --git a/MalApi/AnimeDetailsResults.cs b/MalApi/AnimeDetailsResults.cs index 8a34c01..c92cc8c 100644 --- a/MalApi/AnimeDetailsResults.cs +++ b/MalApi/AnimeDetailsResults.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; namespace MalApi { diff --git a/MalApi/AnimeListCache.cs b/MalApi/AnimeListCache.cs index 4f4418d..ff04988 100644 --- a/MalApi/AnimeListCache.cs +++ b/MalApi/AnimeListCache.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; namespace MalApi diff --git a/MalApi/CachingMyAnimeListApi.cs b/MalApi/CachingMyAnimeListApi.cs index 8d69b2a..a9ca4a2 100644 --- a/MalApi/CachingMyAnimeListApi.cs +++ b/MalApi/CachingMyAnimeListApi.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/MalApi/Genre.cs b/MalApi/Genre.cs index f4c035d..09a4235 100644 --- a/MalApi/Genre.cs +++ b/MalApi/Genre.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace MalApi { diff --git a/MalApi/IMyAnimeListApi.cs b/MalApi/IMyAnimeListApi.cs index a948131..9e34f19 100644 --- a/MalApi/IMyAnimeListApi.cs +++ b/MalApi/IMyAnimeListApi.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/MalApi/Logging.cs b/MalApi/Logging.cs index 0d33298..bf010d9 100644 --- a/MalApi/Logging.cs +++ b/MalApi/Logging.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Common.Logging; -using Common.Logging.Simple; +using Common.Logging; namespace MalApi { diff --git a/MalApi/MalApiException.cs b/MalApi/MalApiException.cs index e3d214d..584bc33 100644 --- a/MalApi/MalApiException.cs +++ b/MalApi/MalApiException.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace MalApi { diff --git a/MalApi/MalApiRequestException.cs b/MalApi/MalApiRequestException.cs index 3993b74..370aecc 100644 --- a/MalApi/MalApiRequestException.cs +++ b/MalApi/MalApiRequestException.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace MalApi { diff --git a/MalApi/MalAppInfoXml.cs b/MalApi/MalAppInfoXml.cs index d19d0b6..b5d4098 100644 --- a/MalApi/MalAppInfoXml.cs +++ b/MalApi/MalAppInfoXml.cs @@ -6,8 +6,6 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Threading; -using MalApi.Anime; -using MalApi.Manga; namespace MalApi { diff --git a/MalApi/MalUserLookupResults.cs b/MalApi/MalUserLookupResults.cs index 19e1ec5..e05b12a 100644 --- a/MalApi/MalUserLookupResults.cs +++ b/MalApi/MalUserLookupResults.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using MalApi.Anime; -using MalApi.Manga; +using System.Collections.Generic; namespace MalApi { diff --git a/MalApi/MalUserNotFoundException.cs b/MalApi/MalUserNotFoundException.cs index feccc3d..255fe14 100644 --- a/MalApi/MalUserNotFoundException.cs +++ b/MalApi/MalUserNotFoundException.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace MalApi { diff --git a/MalApi/Manga/MalMangaInfoFromUserLookup.cs b/MalApi/Manga/MalMangaInfoFromUserLookup.cs index dfa6d66..d511d5d 100644 --- a/MalApi/Manga/MalMangaInfoFromUserLookup.cs +++ b/MalApi/Manga/MalMangaInfoFromUserLookup.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace MalApi.Manga +namespace MalApi { public class MalMangaInfoFromUserLookup : IEquatable { diff --git a/MalApi/Manga/MalMangaSeriesStatus.cs b/MalApi/Manga/MalMangaSeriesStatus.cs index a9b0943..7eb27a7 100644 --- a/MalApi/Manga/MalMangaSeriesStatus.cs +++ b/MalApi/Manga/MalMangaSeriesStatus.cs @@ -1,4 +1,4 @@ -namespace MalApi.Manga +namespace MalApi { public enum MalMangaSeriesStatus { diff --git a/MalApi/Manga/MalMangaType.cs b/MalApi/Manga/MalMangaType.cs index 86f935c..fcce6a5 100644 --- a/MalApi/Manga/MalMangaType.cs +++ b/MalApi/Manga/MalMangaType.cs @@ -1,4 +1,4 @@ -namespace MalApi.Manga +namespace MalApi { public enum MalMangaType { diff --git a/MalApi/Manga/MangaCompletionStatus.cs b/MalApi/Manga/MangaCompletionStatus.cs index 6960e69..caa8953 100644 --- a/MalApi/Manga/MangaCompletionStatus.cs +++ b/MalApi/Manga/MangaCompletionStatus.cs @@ -1,4 +1,4 @@ -namespace MalApi.Manga +namespace MalApi { public enum MangaCompletionStatus { diff --git a/MalApi/Manga/MyMangaListEntry.cs b/MalApi/Manga/MyMangaListEntry.cs index 7c3ca8c..f4932df 100644 --- a/MalApi/Manga/MyMangaListEntry.cs +++ b/MalApi/Manga/MyMangaListEntry.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace MalApi.Manga +namespace MalApi { public class MyMangaListEntry : IEquatable { diff --git a/MalApi/Manga/UpdateMangaObject.cs b/MalApi/Manga/UpdateMangaObject.cs index 2957de6..7d018ba 100644 --- a/MalApi/Manga/UpdateMangaObject.cs +++ b/MalApi/Manga/UpdateMangaObject.cs @@ -1,6 +1,6 @@ using System.Xml.Serialization; -namespace MalApi.Manga +namespace MalApi { [XmlRoot("entry")] public class UpdateMangaObject : UpdateObjectBase diff --git a/MalApi/MyAnimeListApi.cs b/MalApi/MyAnimeListApi.cs index 2aeccef..41d3aa6 100644 --- a/MalApi/MyAnimeListApi.cs +++ b/MalApi/MyAnimeListApi.cs @@ -7,8 +7,6 @@ using System.Net.Http; using System.Threading.Tasks; using System.Threading; -using MalApi.Anime; -using MalApi.Manga; namespace MalApi { diff --git a/MalApi/RateLimitingMyAnimeListApi.cs b/MalApi/RateLimitingMyAnimeListApi.cs index 6bdc45d..1b23c9a 100644 --- a/MalApi/RateLimitingMyAnimeListApi.cs +++ b/MalApi/RateLimitingMyAnimeListApi.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; diff --git a/MalApi/RecentUsersResults.cs b/MalApi/RecentUsersResults.cs index bbdfa9b..d914f0f 100644 --- a/MalApi/RecentUsersResults.cs +++ b/MalApi/RecentUsersResults.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; namespace MalApi { diff --git a/MalApi/RetryOnFailureMyAnimeListApi.cs b/MalApi/RetryOnFailureMyAnimeListApi.cs index 3b6b787..22848c2 100644 --- a/MalApi/RetryOnFailureMyAnimeListApi.cs +++ b/MalApi/RetryOnFailureMyAnimeListApi.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/MalApi/UncertainDate.cs b/MalApi/UncertainDate.cs index 93b514c..2c9723b 100644 --- a/MalApi/UncertainDate.cs +++ b/MalApi/UncertainDate.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace MalApi { From 2b0323e5f37c90400c0f427f82ff013a15460542 Mon Sep 17 00:00:00 2001 From: Shavarsh Movsesyan Date: Sun, 12 Nov 2017 10:43:24 +0200 Subject: [PATCH 3/9] Using directives removal revert. --- MalApi.Example/Program.cs | 3 +++ MalApi.IntegrationTests/GetAnimeDetailsTest.cs | 5 ++++- MalApi.IntegrationTests/GetAnimeListForUserTest.cs | 7 ++++++- MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs | 6 +++++- MalApi.UnitTests/AnimeListCacheTests.cs | 4 ++++ MalApi.UnitTests/Helpers.cs | 6 +++++- MalApi.UnitTests/MalAppInfoXmlTests.cs | 1 + MalApi.UnitTests/MyAnimeListApiTests.cs | 6 +++++- MalApi/Anime/AnimeCompletionStatus.cs | 7 ++++++- MalApi/Anime/MalAnimeInfoFromUserLookup.cs | 2 ++ MalApi/Anime/MalAnimeNotFoundException.cs | 3 +++ MalApi/Anime/MalAnimeSeriesStatus.cs | 7 ++++++- MalApi/Anime/MalAnimeType.cs | 7 ++++++- MalApi/Anime/MyAnimeListEntry.cs | 2 ++ MalApi/AnimeDetailsResults.cs | 5 ++++- MalApi/AnimeListCache.cs | 2 ++ MalApi/CachingMyAnimeListApi.cs | 3 +++ MalApi/Genre.cs | 3 +++ MalApi/IMyAnimeListApi.cs | 3 +++ MalApi/Logging.cs | 7 ++++++- MalApi/MalApiException.cs | 3 +++ MalApi/MalApiRequestException.cs | 3 +++ MalApi/MalUserLookupResults.cs | 5 ++++- MalApi/MalUserNotFoundException.cs | 3 +++ MalApi/Manga/MalMangaInfoFromUserLookup.cs | 2 ++ MalApi/Manga/MyMangaListEntry.cs | 2 ++ MalApi/RateLimitingMyAnimeListApi.cs | 3 +++ MalApi/RecentUsersResults.cs | 5 ++++- MalApi/RetryOnFailureMyAnimeListApi.cs | 3 +++ MalApi/UncertainDate.cs | 3 +++ 30 files changed, 109 insertions(+), 12 deletions(-) diff --git a/MalApi.Example/Program.cs b/MalApi.Example/Program.cs index c450d13..5d72250 100644 --- a/MalApi.Example/Program.cs +++ b/MalApi.Example/Program.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi.Example diff --git a/MalApi.IntegrationTests/GetAnimeDetailsTest.cs b/MalApi.IntegrationTests/GetAnimeDetailsTest.cs index 0a3e4d6..223ee2e 100644 --- a/MalApi.IntegrationTests/GetAnimeDetailsTest.cs +++ b/MalApi.IntegrationTests/GetAnimeDetailsTest.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; using FluentAssertions; diff --git a/MalApi.IntegrationTests/GetAnimeListForUserTest.cs b/MalApi.IntegrationTests/GetAnimeListForUserTest.cs index 0cad446..615d953 100644 --- a/MalApi.IntegrationTests/GetAnimeListForUserTest.cs +++ b/MalApi.IntegrationTests/GetAnimeListForUserTest.cs @@ -1,4 +1,9 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MalApi; +using System.Threading.Tasks; using Xunit; using System.Threading; diff --git a/MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs b/MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs index 6b24b23..6bb881a 100644 --- a/MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs +++ b/MalApi.IntegrationTests/GetRecentOnlineUsersTest.cs @@ -1,4 +1,8 @@ -using System.Threading; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; using System.Threading.Tasks; using Xunit; diff --git a/MalApi.UnitTests/AnimeListCacheTests.cs b/MalApi.UnitTests/AnimeListCacheTests.cs index 972d52b..bb8c629 100644 --- a/MalApi.UnitTests/AnimeListCacheTests.cs +++ b/MalApi.UnitTests/AnimeListCacheTests.cs @@ -1,5 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; +using MalApi; +using System.Threading; using Xunit; namespace MalApi.UnitTests diff --git a/MalApi.UnitTests/Helpers.cs b/MalApi.UnitTests/Helpers.cs index 08e1337..4b686b5 100644 --- a/MalApi.UnitTests/Helpers.cs +++ b/MalApi.UnitTests/Helpers.cs @@ -1,6 +1,10 @@ -using System.IO; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Reflection; using System.Text; +using System.Threading.Tasks; namespace MalApi.UnitTests { diff --git a/MalApi.UnitTests/MalAppInfoXmlTests.cs b/MalApi.UnitTests/MalAppInfoXmlTests.cs index 4bcea0f..61359dd 100644 --- a/MalApi.UnitTests/MalAppInfoXmlTests.cs +++ b/MalApi.UnitTests/MalAppInfoXmlTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.IO; using System.Xml.Linq; using FluentAssertions; diff --git a/MalApi.UnitTests/MyAnimeListApiTests.cs b/MalApi.UnitTests/MyAnimeListApiTests.cs index a78412e..efb50ba 100644 --- a/MalApi.UnitTests/MyAnimeListApiTests.cs +++ b/MalApi.UnitTests/MyAnimeListApiTests.cs @@ -1,4 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; using System.IO; using FluentAssertions; using Xunit; diff --git a/MalApi/Anime/AnimeCompletionStatus.cs b/MalApi/Anime/AnimeCompletionStatus.cs index 6b4d000..98c4e0c 100644 --- a/MalApi/Anime/AnimeCompletionStatus.cs +++ b/MalApi/Anime/AnimeCompletionStatus.cs @@ -1,4 +1,9 @@ -namespace MalApi +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MalApi { public enum AnimeCompletionStatus { diff --git a/MalApi/Anime/MalAnimeInfoFromUserLookup.cs b/MalApi/Anime/MalAnimeInfoFromUserLookup.cs index e1acec4..a225801 100644 --- a/MalApi/Anime/MalAnimeInfoFromUserLookup.cs +++ b/MalApi/Anime/MalAnimeInfoFromUserLookup.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/Anime/MalAnimeNotFoundException.cs b/MalApi/Anime/MalAnimeNotFoundException.cs index b76a065..69d712f 100644 --- a/MalApi/Anime/MalAnimeNotFoundException.cs +++ b/MalApi/Anime/MalAnimeNotFoundException.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/Anime/MalAnimeSeriesStatus.cs b/MalApi/Anime/MalAnimeSeriesStatus.cs index ce5607e..144da1d 100644 --- a/MalApi/Anime/MalAnimeSeriesStatus.cs +++ b/MalApi/Anime/MalAnimeSeriesStatus.cs @@ -1,4 +1,9 @@ -namespace MalApi +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MalApi { public enum MalAnimeSeriesStatus { diff --git a/MalApi/Anime/MalAnimeType.cs b/MalApi/Anime/MalAnimeType.cs index 9205bea..6fbab88 100644 --- a/MalApi/Anime/MalAnimeType.cs +++ b/MalApi/Anime/MalAnimeType.cs @@ -1,4 +1,9 @@ -namespace MalApi +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MalApi { public enum MalAnimeType { diff --git a/MalApi/Anime/MyAnimeListEntry.cs b/MalApi/Anime/MyAnimeListEntry.cs index e67af66..2482b22 100644 --- a/MalApi/Anime/MyAnimeListEntry.cs +++ b/MalApi/Anime/MyAnimeListEntry.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/AnimeDetailsResults.cs b/MalApi/AnimeDetailsResults.cs index c92cc8c..8a34c01 100644 --- a/MalApi/AnimeDetailsResults.cs +++ b/MalApi/AnimeDetailsResults.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/AnimeListCache.cs b/MalApi/AnimeListCache.cs index ff04988..4f4418d 100644 --- a/MalApi/AnimeListCache.cs +++ b/MalApi/AnimeListCache.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; using System.Threading; namespace MalApi diff --git a/MalApi/CachingMyAnimeListApi.cs b/MalApi/CachingMyAnimeListApi.cs index a9ca4a2..8d69b2a 100644 --- a/MalApi/CachingMyAnimeListApi.cs +++ b/MalApi/CachingMyAnimeListApi.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/MalApi/Genre.cs b/MalApi/Genre.cs index 09a4235..f4c035d 100644 --- a/MalApi/Genre.cs +++ b/MalApi/Genre.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/IMyAnimeListApi.cs b/MalApi/IMyAnimeListApi.cs index 9e34f19..a948131 100644 --- a/MalApi/IMyAnimeListApi.cs +++ b/MalApi/IMyAnimeListApi.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/MalApi/Logging.cs b/MalApi/Logging.cs index bf010d9..0d33298 100644 --- a/MalApi/Logging.cs +++ b/MalApi/Logging.cs @@ -1,4 +1,9 @@ -using Common.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Common.Logging; +using Common.Logging.Simple; namespace MalApi { diff --git a/MalApi/MalApiException.cs b/MalApi/MalApiException.cs index 584bc33..e3d214d 100644 --- a/MalApi/MalApiException.cs +++ b/MalApi/MalApiException.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/MalApiRequestException.cs b/MalApi/MalApiRequestException.cs index 370aecc..3993b74 100644 --- a/MalApi/MalApiRequestException.cs +++ b/MalApi/MalApiRequestException.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/MalUserLookupResults.cs b/MalApi/MalUserLookupResults.cs index e05b12a..8b8245e 100644 --- a/MalApi/MalUserLookupResults.cs +++ b/MalApi/MalUserLookupResults.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/MalUserNotFoundException.cs b/MalApi/MalUserNotFoundException.cs index 255fe14..feccc3d 100644 --- a/MalApi/MalUserNotFoundException.cs +++ b/MalApi/MalUserNotFoundException.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/Manga/MalMangaInfoFromUserLookup.cs b/MalApi/Manga/MalMangaInfoFromUserLookup.cs index d511d5d..5f5c3d2 100644 --- a/MalApi/Manga/MalMangaInfoFromUserLookup.cs +++ b/MalApi/Manga/MalMangaInfoFromUserLookup.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/Manga/MyMangaListEntry.cs b/MalApi/Manga/MyMangaListEntry.cs index f4932df..40d41a4 100644 --- a/MalApi/Manga/MyMangaListEntry.cs +++ b/MalApi/Manga/MyMangaListEntry.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/RateLimitingMyAnimeListApi.cs b/MalApi/RateLimitingMyAnimeListApi.cs index 1b23c9a..6bdc45d 100644 --- a/MalApi/RateLimitingMyAnimeListApi.cs +++ b/MalApi/RateLimitingMyAnimeListApi.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; diff --git a/MalApi/RecentUsersResults.cs b/MalApi/RecentUsersResults.cs index d914f0f..bbdfa9b 100644 --- a/MalApi/RecentUsersResults.cs +++ b/MalApi/RecentUsersResults.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { diff --git a/MalApi/RetryOnFailureMyAnimeListApi.cs b/MalApi/RetryOnFailureMyAnimeListApi.cs index 22848c2..3b6b787 100644 --- a/MalApi/RetryOnFailureMyAnimeListApi.cs +++ b/MalApi/RetryOnFailureMyAnimeListApi.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/MalApi/UncertainDate.cs b/MalApi/UncertainDate.cs index 2c9723b..93b514c 100644 --- a/MalApi/UncertainDate.cs +++ b/MalApi/UncertainDate.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace MalApi { From 5b90a8fc129a42d878ccf926c0a42305d95a194c Mon Sep 17 00:00:00 2001 From: Shavarsh Movsesyan Date: Sun, 12 Nov 2017 23:59:20 +0200 Subject: [PATCH 4/9] Addressed almost all of your comments. Regarding the response from the update: there are two ways to break the XML - in the first scenario it returns a message for invalid XML and in the other it a MySQL error and status OK ("Updated"). Unfortunately the response does not contain the MySQL information bit. On the other hand I don't know how you can break the XML with the current configuration. When credentials are not correct the already existing code takes care of it and returns a 401. --- MalApi.Example/Program.cs | 21 ++- MalApi/Anime/AnimeCompletionStatus.cs | 7 + MalApi/Anime/UpdateAnime.cs | 215 ++++++++++++++++++++++++ MalApi/Anime/UpdateAnimeObject.cs | 85 ---------- MalApi/Manga/MangaCompletionStatus.cs | 10 +- MalApi/Manga/UpdateManga.cs | 224 ++++++++++++++++++++++++++ MalApi/Manga/UpdateMangaObject.cs | 90 ----------- MalApi/MyAnimeListApi.cs | 122 +++++++------- MalApi/UpdateObjectBase.cs | 3 +- 9 files changed, 530 insertions(+), 247 deletions(-) create mode 100644 MalApi/Anime/UpdateAnime.cs delete mode 100644 MalApi/Anime/UpdateAnimeObject.cs create mode 100644 MalApi/Manga/UpdateManga.cs delete mode 100644 MalApi/Manga/UpdateMangaObject.cs diff --git a/MalApi.Example/Program.cs b/MalApi.Example/Program.cs index 5d72250..f185b9c 100644 --- a/MalApi.Example/Program.cs +++ b/MalApi.Example/Program.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; @@ -25,11 +26,23 @@ static void Main(string[] args) api.UserAgent = "MalApiExample"; api.TimeoutInMs = 15000; - var animeUpdateInfo = new UpdateAnimeObject(episode: "26", status: "2", score: "9"); - string userLookup2 = api.UpdateAnimeForUser(1, animeUpdateInfo, "user", "pass"); + var animeUpdateInfo = new UpdateAnime() + { + Episode = 26, + Status = AnimeCompletionStatus.Completed, + Score = 9, + DateStart = new DateTime(1999, 01, 02) + }; + string userUpdateAnime = api.UpdateAnimeForUser(1, animeUpdateInfo, "user", "password"); - var mangaUpdateInfo = new UpdateMangaObject(chapter: "20", volume: "3", score: "8"); - string userLookup3 = api.UpdateMangaForUser(952, mangaUpdateInfo, "user", "pass"); + var mangaUpdateInfo = new UpdateManga() + { + Chapter = 20, + Volume = 3, + Score = 8, + Status = MangaCompletionStatus.Completed + }; + string userUpdateManga = api.UpdateMangaForUser(952, mangaUpdateInfo, "user", "password"); diff --git a/MalApi/Anime/AnimeCompletionStatus.cs b/MalApi/Anime/AnimeCompletionStatus.cs index 98c4e0c..9a9c0b9 100644 --- a/MalApi/Anime/AnimeCompletionStatus.cs +++ b/MalApi/Anime/AnimeCompletionStatus.cs @@ -2,15 +2,22 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Xml.Serialization; namespace MalApi { + // XML enum attributes are needed for proper serialization upon sending an update request public enum AnimeCompletionStatus { + [XmlEnum(Name = "watching")] Watching = 1, + [XmlEnum(Name = "completed")] Completed = 2, + [XmlEnum(Name = "onhold")] OnHold = 3, + [XmlEnum(Name = "dropped")] Dropped = 4, + [XmlEnum(Name = "plantowatch")] PlanToWatch = 6, } } diff --git a/MalApi/Anime/UpdateAnime.cs b/MalApi/Anime/UpdateAnime.cs new file mode 100644 index 0000000..1c21182 --- /dev/null +++ b/MalApi/Anime/UpdateAnime.cs @@ -0,0 +1,215 @@ +using System; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace MalApi +{ + /// + /// The update object sent to MAL when updating an anime entry. + /// Only specified values will be changed. The rest will remain unchanged. + /// More details: https://myanimelist.net/modules.php?go=api#animevalues + /// + [XmlRoot("entry")] + public class UpdateAnime : UpdateObjectBase, IXmlSerializable + { + [XmlElement("episode")] + public int? Episode { get; set; } = null; + + [XmlElement("status")] + public AnimeCompletionStatus? Status { get; set; } = null; + + [XmlElement("score")] + public int? Score { get; set; } = null; + + [XmlElement("storage_type")] + public int? StorageType { get; set; } = null; + + [XmlElement("storage_value")] + public float? StorageValue { get; set; } = null; + + [XmlElement("times_rewatched")] + public int? TimesRewatched { get; set; } = null; + + [XmlElement("rewatch_value")] + public int? RewatchValue { get; set; } = null; + + [XmlIgnore] + public DateTime? DateStart { get; set; } = null; + + [XmlElement("date_start")] + private string FormattedDateStart + { + get + { + return DateStart?.ToString("MMddyyyy"); + } + set + { + DateStart = DateTime.Parse(value); + } + } + + public DateTime? DateFinish { get; set; } = null; + + [XmlElement("date_finish")] + private string FormattedDateFinish + { + get + { + return DateFinish?.ToString("MMddyyyy"); + } + set + { + DateFinish = DateTime.Parse(value); + } + } + + [XmlElement("priority")] + public int? Priority { get; set; } = null; + + [XmlElement("enable_discussion")] + public int? EnableDiscussion { get; set; } = null; + + [XmlElement("enable_rewatching")] + public int? EnableRewatching { get; set; } = null; + + [XmlElement("comments")] + public string Comments { get; set; } = null; + + [XmlElement("tags")] + public string Tags { get; set; } = null; + + #region IXmlSerializable implementation + + public XmlSchema GetSchema() + { + return null; + } + + // 12.11.17 - MAL API does not return this structure + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + // Episode + writer.WriteStartElement("episode"); + if (Episode != null) + { + writer.WriteValue(Episode); + } + writer.WriteEndElement(); + + // Status + writer.WriteStartElement("status"); + if (Status != null) + { + writer.WriteString(Status.Value.ToString().ToLower()); + } + writer.WriteEndElement(); + + // Score + writer.WriteStartElement("score"); + if (Score != null) + { + writer.WriteValue(Score); + } + writer.WriteEndElement(); + + // Storage type + writer.WriteStartElement("storage_type"); + if (StorageType != null) + { + writer.WriteValue(StorageType); + } + writer.WriteEndElement(); + + // Storage value + writer.WriteStartElement("storage_value"); + if (StorageValue != null) + { + writer.WriteValue(StorageValue); + } + writer.WriteEndElement(); + + // Times rewatched + writer.WriteStartElement("times_rewatched"); + if (TimesRewatched != null) + { + writer.WriteValue(TimesRewatched); + } + writer.WriteEndElement(); + + // Rewatch value + writer.WriteStartElement("rewatch_value"); + if (RewatchValue != null) + { + writer.WriteValue(RewatchValue); + } + writer.WriteEndElement(); + + // Date start (formatted) + writer.WriteStartElement("date_start"); + if (FormattedDateStart != null) + { + writer.WriteString(FormattedDateStart); + } + writer.WriteEndElement(); + + // Date finish (formatted) + writer.WriteStartElement("date_finish"); + if (FormattedDateFinish != null) + { + writer.WriteString(FormattedDateFinish); + } + writer.WriteEndElement(); + + // Priority + writer.WriteStartElement("priority"); + if (Priority != null) + { + writer.WriteValue(Priority); + } + writer.WriteEndElement(); + + // Enable discussion + writer.WriteStartElement("enable_discussion"); + if (EnableDiscussion != null) + { + writer.WriteValue(EnableDiscussion); + } + writer.WriteEndElement(); + + // Enable rewatching + writer.WriteStartElement("enable_rewatching"); + if (EnableRewatching != null) + { + writer.WriteValue(EnableRewatching); + } + writer.WriteEndElement(); + + // Enable comments + writer.WriteStartElement("comments"); + if (Comments != null) + + { + writer.WriteString(Comments); + } + writer.WriteEndElement(); + + // Tags + writer.WriteStartElement("tags"); + if (Tags != null) + + { + writer.WriteString(Tags); + } + writer.WriteEndElement(); + } + + #endregion + } +} diff --git a/MalApi/Anime/UpdateAnimeObject.cs b/MalApi/Anime/UpdateAnimeObject.cs deleted file mode 100644 index 1b8e090..0000000 --- a/MalApi/Anime/UpdateAnimeObject.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Xml.Serialization; - -namespace MalApi -{ - [XmlRoot("entry")] - public class UpdateAnimeObject : UpdateObjectBase - { - [XmlElement("episode")] - public string Episode { get; set; } = null; - - [XmlElement("status")] - public string Status { get; set; } = null; - - [XmlElement("score")] - public string Score { get; set; } = null; - - [XmlElement("storage_type")] - public string StorageType { get; set; } = null; - - [XmlElement("storage_value")] - public string StorageValue { get; set; } = null; - - [XmlElement("times_rewatched")] - public string TimesRewatched { get; set; } = null; - - [XmlElement("rewatch_value")] - public string RewatchValue { get; set; } = null; - - [XmlElement("date_start")] - public string DateStart { get; set; } = null; - - [XmlElement("date_finish")] - public string DateFinish { get; set; } = null; - - [XmlElement("priority")] - public string Priority { get; set; } = null; - - [XmlElement("enable_discussion")] - public string EnableDiscussion { get; set; } = null; - - [XmlElement("enable_rewatching")] - public string EnableRewatching { get; set; } = null; - - [XmlElement("comments")] - public string Comments { get; set; } = null; - - [XmlElement("tags")] - public string Tags { get; set; } = null; - - private UpdateAnimeObject() - { - } - - public UpdateAnimeObject(string episode = null, - string status = null, - string score = null, - string storageType = null, - string storageValue = null, - string timesRewatched = null, - string rewatchValue = null, - string dateStart = null, - string dateFinish = null, - string priority = null, - string enableDiscussion = null, - string enableRewatching = null, - string comments = null, - string tags = null) - { - Episode = episode; - Status = status; - Score = score; - StorageType = storageType; - StorageValue = storageValue; - TimesRewatched = timesRewatched; - RewatchValue = rewatchValue; - DateStart = dateStart; - DateFinish = dateFinish; - Priority = priority; - EnableDiscussion = enableDiscussion; - EnableRewatching = enableRewatching; - Comments = comments; - Tags = tags; - } - } -} diff --git a/MalApi/Manga/MangaCompletionStatus.cs b/MalApi/Manga/MangaCompletionStatus.cs index caa8953..16af162 100644 --- a/MalApi/Manga/MangaCompletionStatus.cs +++ b/MalApi/Manga/MangaCompletionStatus.cs @@ -1,11 +1,19 @@ -namespace MalApi +using System.Xml.Serialization; + +namespace MalApi { + // XML enum attributes are needed for proper serialization upon sending an update request public enum MangaCompletionStatus { + [XmlEnum(Name = "reading")] Reading = 1, + [XmlEnum(Name = "completed")] Completed = 2, + [XmlEnum(Name = "onhold")] OnHold = 3, + [XmlEnum(Name = "dropped")] Dropped = 4, + [XmlEnum(Name = "plantoread")] PlanToRead = 6, } } \ No newline at end of file diff --git a/MalApi/Manga/UpdateManga.cs b/MalApi/Manga/UpdateManga.cs new file mode 100644 index 0000000..b4ddfbf --- /dev/null +++ b/MalApi/Manga/UpdateManga.cs @@ -0,0 +1,224 @@ +using System; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace MalApi +{ + /// + /// The update object sent to MAL when updating a manga entry. + /// Only specified values will be changed. The rest will remain unchanged. + /// More details: https://myanimelist.net/modules.php?go=api#mangavalues + /// + [XmlRoot("entry")] + public class UpdateManga : UpdateObjectBase, IXmlSerializable + { + [XmlElement("chapter")] + public int? Chapter { get; set; } = null; + + [XmlElement("volume")] + public int? Volume { get; set; } = null; + + [XmlElement("status")] + public MangaCompletionStatus? Status { get; set; } = null; + + [XmlElement("score")] + public int? Score { get; set; } = null; + + [XmlElement("times_reread")] + public int? TimesReread { get; set; } = null; + + [XmlElement("reread_value")] + public int? RereadValue { get; set; } = null; + + [XmlIgnore] + public DateTime? DateStart { get; set; } = null; + + [XmlElement("date_start")] + private string FormattedDateStart + { + get + { + return DateStart?.ToString("MMddyyyy"); + } + set + { + DateStart = DateTime.Parse(value); + } + } + + public DateTime? DateFinish { get; set; } = null; + + [XmlElement("date_finish")] + private string FormattedDateFinish + { + get + { + return DateFinish?.ToString("MMddyyyy"); + } + set + { + DateFinish = DateTime.Parse(value); + } + } + + [XmlElement("priority")] + public int? Priority { get; set; } = null; + + [XmlElement("enable_discussion")] + public int? EnableDiscussion { get; set; } = null; + + [XmlElement("enable_rereading")] + public int? EnableRereading { get; set; } = null; + + [XmlElement("comments")] + public string Comments { get; set; } = null; + + [XmlElement("scan_group")] + public string ScanGroup { get; set; } = null; + + [XmlElement("tags")] + public string Tags { get; set; } = null; + + [XmlElement("retail_volumes")] + public int? RetailVolumes { get; set; } = null; + + #region IXmlSerializable implementation + + public XmlSchema GetSchema() + { + return null; + } + + // 12.11.17 - MAL API does not return this structure + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + // Episode + writer.WriteStartElement("chapter"); + if (Chapter != null) + { + writer.WriteValue(Chapter); + } + writer.WriteEndElement(); + + // Volume + writer.WriteStartElement("volume"); + if (Volume != null) + { + writer.WriteValue(Volume); + } + writer.WriteEndElement(); + + // Status + writer.WriteStartElement("status"); + if (Status != null) + { + writer.WriteString(Status.Value.ToString().ToLower()); + } + writer.WriteEndElement(); + + // Score + writer.WriteStartElement("score"); + if (Score != null) + { + writer.WriteValue(Score); + } + writer.WriteEndElement(); + + // Times reread + writer.WriteStartElement("times_reread"); + if (TimesReread != null) + { + writer.WriteValue(TimesReread); + } + writer.WriteEndElement(); + + // Reread value + writer.WriteStartElement("reread_value"); + if (RereadValue != null) + { + writer.WriteValue(RereadValue); + } + writer.WriteEndElement(); + + // Date start (formatted) + writer.WriteStartElement("date_start"); + if (FormattedDateStart != null) + { + writer.WriteString(FormattedDateStart); + } + writer.WriteEndElement(); + + // Date finish (formatted) + writer.WriteStartElement("date_finish"); + if (FormattedDateFinish != null) + { + writer.WriteString(FormattedDateFinish); + } + writer.WriteEndElement(); + + // Priority + writer.WriteStartElement("priority"); + if (Priority != null) + { + writer.WriteValue(Priority); + } + writer.WriteEndElement(); + + // Enable discussion + writer.WriteStartElement("enable_discussion"); + if (EnableDiscussion != null) + { + writer.WriteValue(EnableDiscussion); + } + writer.WriteEndElement(); + + // Enable rereading + writer.WriteStartElement("enable_rereading"); + if (EnableRereading != null) + { + writer.WriteValue(EnableRereading); + } + writer.WriteEndElement(); + + // Comments + writer.WriteStartElement("comments"); + if (Comments != null) + { + writer.WriteString(Comments); + } + writer.WriteEndElement(); + + // Scan group + writer.WriteStartElement("scan_group"); + if (ScanGroup != null) + { + writer.WriteString(ScanGroup); + } + writer.WriteEndElement(); + + // Tags + writer.WriteStartElement("tags"); + if (Tags != null) + { + writer.WriteString(Tags); + } + writer.WriteEndElement(); + + // Retail volumes + writer.WriteStartElement("retail_volumes"); + if (RetailVolumes != null) + { + writer.WriteValue(RetailVolumes); + } + writer.WriteEndElement(); + } + + #endregion + } +} diff --git a/MalApi/Manga/UpdateMangaObject.cs b/MalApi/Manga/UpdateMangaObject.cs deleted file mode 100644 index 7d018ba..0000000 --- a/MalApi/Manga/UpdateMangaObject.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Xml.Serialization; - -namespace MalApi -{ - [XmlRoot("entry")] - public class UpdateMangaObject : UpdateObjectBase - { - [XmlElement("chapter")] - public string Chapter { get; set; } = null; - - [XmlElement("volume")] - public string Volume { get; set; } = null; - - [XmlElement("status")] - public string Status { get; set; } = null; - - [XmlElement("score")] - public string Score { get; set; } = null; - - [XmlElement("times_reread")] - public string TimesReread { get; set; } = null; - - [XmlElement("reread_value")] - public string RereadValue { get; set; } = null; - - [XmlElement("date_start")] - public string DateStart { get; set; } = null; - - [XmlElement("date_finish")] - public string DateFinish { get; set; } = null; - - [XmlElement("priority")] - public string Priority { get; set; } = null; - - [XmlElement("enable_discussion")] - public string EnableDiscussion { get; set; } = null; - - [XmlElement("enable_rereading")] - public string EnableRereading { get; set; } = null; - - [XmlElement("comments")] - public string Comments { get; set; } = null; - - [XmlElement("scan_group")] - public string ScanGroup { get; set; } = null; - - [XmlElement("tags")] - public string Tags { get; set; } = null; - - [XmlElement("retail_volumes")] - public string RetailVolumes { get; set; } = null; - - public UpdateMangaObject() - { - } - - public UpdateMangaObject(string chapter = null, - string volume = null, - string status = null, - string score = null, - string timesReread = null, - string rereadValue = null, - string dateStart = null, - string dateFinish = null, - string priority = null, - string enableDiscussion = null, - string enableRereading = null, - string comments = null, - string scanGroup = null, - string tags = null, - string retailVolumes = null) - { - Chapter = chapter; - Volume = volume; - Status = status; - Score = score; - TimesReread = timesReread; - RereadValue = rereadValue; - DateStart = dateStart; - DateFinish = dateFinish; - Priority = priority; - EnableDiscussion = enableDiscussion; - EnableRereading = enableRereading; - Comments = comments; - ScanGroup = scanGroup; - Tags = tags; - RetailVolumes = retailVolumes; - } - } -} diff --git a/MalApi/MyAnimeListApi.cs b/MalApi/MyAnimeListApi.cs index 41d3aa6..2766a8a 100644 --- a/MalApi/MyAnimeListApi.cs +++ b/MalApi/MyAnimeListApi.cs @@ -5,6 +5,7 @@ using System.IO; using System.Text.RegularExpressions; using System.Net.Http; +using System.Net.Http.Headers; using System.Threading.Tasks; using System.Threading; @@ -17,12 +18,6 @@ public class MyAnimeListApi : IMyAnimeListApi { private static readonly string AnimeDetailsUrlFormat = "https://myanimelist.net/anime/{0}"; - private const string MalAppAnimeInfoUri = "https://myanimelist.net/malappinfo.php?status=all&type=anime&u={0}"; - private const string MalAppMangaInfoUri = "https://myanimelist.net/malappinfo.php?status=all&type=manga&u={0}"; - - private const string MalAppAnimeUpdateUri = "https://myanimelist.net/api/animelist/update/{0}.xml"; - private const string MalAppMangaUpdateUri = "https://myanimelist.net/api/mangalist/update/{0}.xml"; - private const string RecentOnlineUsersUri = "https://myanimelist.net/users.php"; /// @@ -78,36 +73,30 @@ private HttpRequestMessage InitNewRequest(string uri, HttpMethod method) return request; } - private HttpRequestMessage InitNewRequestWithCredentials(string user, string password, string uri, HttpMethod method, UpdateObjectBase updateInfo = null) + private HttpRequestMessage InitNewRequestWithCredentials(string uri, HttpMethod method, string user, string password) { - HttpRequestMessage request = new HttpRequestMessage(method, uri); + HttpRequestMessage request = InitNewRequest(uri, method); // Requests with credentials require them to be encoded in base64 string credentials; if (user != null && password != null) { - var plainTextBytes = Encoding.UTF8.GetBytes(user + ":" + password); - credentials = Convert.ToBase64String(plainTextBytes); + byte[] plainTextBytes = Encoding.UTF8.GetBytes(user + ":" + password); + credentials = Convert.ToBase64String(plainTextBytes); } else { - throw new Exception("Invalid input credentials format (both username and password have to be input OR just the base64 representation"); - } + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } - if (UserAgent != null) - { - request.Headers.TryAddWithoutValidation("User-Agent", UserAgent); - // Adding the authorization header with the credentials - request.Headers.TryAddWithoutValidation("Authorization", "Basic " + credentials); + // This will always be true given the && condition above + throw new ArgumentNullException(nameof(password)); } - // Encoding and adding the new information in the content(body) of the request - if(updateInfo != null) - { - var xml = updateInfo.GenerateXml(); - var content = "data=" + WebUtility.UrlEncode(xml); - request.Content = new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded"); - } + // Adding the authorization header with the credentials + request.Headers.Authorization = new AuthenticationHeaderValue("Basic", credentials); return request; } @@ -229,7 +218,7 @@ public Task GetAnimeListForUserAsync(string user) /// /// /// - public Task UpdateAnimeForUserAsync(int animeId, UpdateAnimeObject updateInfo, string user, string password) + public Task UpdateAnimeForUserAsync(int animeId, UpdateAnime updateInfo, string user, string password) { return UpdateAnimeForUserAsync(animeId, updateInfo, user, password, CancellationToken.None); } @@ -254,7 +243,7 @@ public Task GetMangaListForUserAsync(string user) /// /// /// - public Task UpdateMangaForUserAsync(int mangaId, UpdateMangaObject updateInfo, string user, string password) + public Task UpdateMangaForUserAsync(int mangaId, UpdateManga updateInfo, string user, string password) { return UpdateMangaForUserAsync(mangaId, updateInfo, user, password, CancellationToken.None); } @@ -269,7 +258,9 @@ public Task UpdateMangaForUserAsync(int mangaId, UpdateMangaObject updat /// public async Task GetAnimeListForUserAsync(string user, CancellationToken cancellationToken) { - string userInfoUri = string.Format(MalAppAnimeInfoUri, Uri.EscapeDataString(user)); + const string malAppAnimeInfoUriFormatString = "https://myanimelist.net/malappinfo.php?status=all&type=anime&u={0}"; + + string userInfoUri = string.Format(malAppAnimeInfoUriFormatString, Uri.EscapeDataString(user)); Logging.Log.InfoFormat("Getting anime list for MAL user {0} using URI {1}", user, userInfoUri); @@ -291,8 +282,10 @@ public async Task GetAnimeListForUserAsync(string user, Ca try { HttpRequestMessage request = InitNewRequest(userInfoUri, HttpMethod.Get); - MalUserLookupResults parsedList = await ProcessRequestAsync(request, responseProcessingFunc, cancellationToken: cancellationToken, - baseErrorMessage: string.Format("Failed getting anime list for user {0} using url {1}", user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); + MalUserLookupResults parsedList = await ProcessRequestAsync(request, responseProcessingFunc, + cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed getting anime list for user {0} using url {1}", user, + userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); Logging.Log.InfoFormat("Successfully retrieved anime list for user {0}", user); return parsedList; @@ -310,40 +303,36 @@ public async Task GetAnimeListForUserAsync(string user, Ca /// ID of the anime /// The updated information /// - /// MAL user + /// MAL username /// MAL password /// - public async Task UpdateAnimeForUserAsync(int animeId, UpdateAnimeObject updateInfo, string user, string password, CancellationToken cancellationToken) + public async Task UpdateAnimeForUserAsync(int animeId, UpdateAnime updateInfo, string user, string password, CancellationToken cancellationToken) { - string userInfoUri = string.Format(MalAppAnimeUpdateUri, Uri.EscapeDataString(animeId.ToString())); + const string malAnimeUpdateUriFormatString = "https://myanimelist.net/api/animelist/update/{0}.xml"; + + string userInfoUri = string.Format(malAnimeUpdateUriFormatString, Uri.EscapeDataString(animeId.ToString())); Logging.Log.InfoFormat("Updating anime entry for MAL anime ID {0}, user {1} using URI {2}", animeId, user, userInfoUri); Func responseProcessingFunc = (response) => { - using (TextReader xmlTextReader = new StringReader(response)) - { - try - { - return xmlTextReader.ToString(); - } - catch (Exception ex) - { - throw new Exception(string.Format("Exception for user {0} and anime ID {1}.", user, animeId), ex); - } - } + return response; }; try { - HttpRequestMessage request = InitNewRequestWithCredentials(user, password, userInfoUri, HttpMethod.Post, updateInfo); + HttpRequestMessage request = InitNewRequestWithCredentials(userInfoUri, HttpMethod.Post, user, password); + + // Encoding and adding the new information in the content(body) of the request + string xml = updateInfo.GenerateXml(); + request.Content = new FormUrlEncodedContent(new KeyValuePair[] { new KeyValuePair("data", xml) }); string result = await ProcessRequestAsync(request, responseProcessingFunc, cancellationToken: cancellationToken, baseErrorMessage: string.Format("Failed updating anime entry for anime ID {0}, user {0} using url {1}", animeId, user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); Logging.Log.InfoFormat("Successfully updated anime entry for anime ID {0} and user {0}", animeId, user); - return null; + return result; } catch (OperationCanceledException) { @@ -360,9 +349,12 @@ public async Task UpdateAnimeForUserAsync(int animeId, UpdateAnimeObject /// /// /// - public async Task GetMangaListForUserAsync(string user, CancellationToken cancellationToken) + public async Task GetMangaListForUserAsync(string user, + CancellationToken cancellationToken) { - string userInfoUri = string.Format(MalAppMangaInfoUri, Uri.EscapeDataString(user)); + const string malAppMangaInfoUriFormatString = "https://myanimelist.net/malappinfo.php?status=all&type=manga&u={0}"; + + string userInfoUri = string.Format(malAppMangaInfoUriFormatString, Uri.EscapeDataString(user)); Logging.Log.InfoFormat("Getting manga list for MAL user {0} using URI {1}", user, userInfoUri); @@ -384,8 +376,10 @@ public async Task GetMangaListForUserAsync(string user, Ca try { HttpRequestMessage request = InitNewRequest(userInfoUri, HttpMethod.Get); - MalUserLookupResults parsedList = await ProcessRequestAsync(request, responseProcessingFunc, cancellationToken: cancellationToken, - baseErrorMessage: string.Format("Failed getting manga list for user {0} using url {1}", user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); + MalUserLookupResults parsedList = await ProcessRequestAsync(request, responseProcessingFunc, + cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed getting manga list for user {0} using url {1}", user, + userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); Logging.Log.InfoFormat("Successfully retrieved manga list for user {0}", user); return parsedList; @@ -406,37 +400,33 @@ public async Task GetMangaListForUserAsync(string user, Ca /// MAL user /// MAL password /// - public async Task UpdateMangaForUserAsync(int mangaId, UpdateMangaObject updateInfo, string user, string password, CancellationToken cancellationToken) + public async Task UpdateMangaForUserAsync(int mangaId, UpdateManga updateInfo, string user, string password, CancellationToken cancellationToken) { - string userInfoUri = string.Format(MalAppMangaUpdateUri, Uri.EscapeDataString(mangaId.ToString())); + const string malMangaUpdateUriFormatString = "https://myanimelist.net/api/mangalist/update/{0}.xml"; + + string userInfoUri = string.Format(malMangaUpdateUriFormatString, Uri.EscapeDataString(mangaId.ToString())); Logging.Log.InfoFormat("Updating manga entry for MAL manga ID {0}, user {1} using URI {2}", mangaId, user, userInfoUri); Func responseProcessingFunc = (response) => { - using (TextReader xmlTextReader = new StringReader(response)) - { - try - { - return xmlTextReader.ToString(); - } - catch (Exception ex) - { - throw new Exception(string.Format("Exception for user {0} and manga ID {1}.", user, mangaId), ex); - } - } + return response; }; try { - HttpRequestMessage request = InitNewRequestWithCredentials(user, password, userInfoUri, HttpMethod.Post, updateInfo); + HttpRequestMessage request = InitNewRequestWithCredentials(userInfoUri, HttpMethod.Post, user, password); + + // Encoding and adding the new information in the content(body) of the request + string xml = updateInfo.GenerateXml(); + request.Content = new FormUrlEncodedContent(new KeyValuePair[] { new KeyValuePair("data", xml) }); string result = await ProcessRequestAsync(request, responseProcessingFunc, cancellationToken: cancellationToken, baseErrorMessage: string.Format("Failed updating manga entry for manga ID {0}, user {0} using url {1}", mangaId, user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); Logging.Log.InfoFormat("Successfully updated manga entry for manga ID {0} and user {0}", mangaId, user); - return null; + return result; } catch (OperationCanceledException) { @@ -466,7 +456,7 @@ public MalUserLookupResults GetAnimeListForUser(string user) /// Password /// base64 encrypted username and password /// - public string UpdateAnimeForUser(int animeId, UpdateAnimeObject updateInfo, string user, string password) + public string UpdateAnimeForUser(int animeId, UpdateAnime updateInfo, string user, string password) { return UpdateAnimeForUserAsync(animeId, updateInfo, user, password).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); } @@ -492,7 +482,7 @@ public MalUserLookupResults GetMangaListForUser(string user) /// Password /// base64 encrypted username and password /// - public string UpdateMangaForUser(int mangaId, UpdateMangaObject updateInfo, string user, string password) + public string UpdateMangaForUser(int mangaId, UpdateManga updateInfo, string user, string password) { return UpdateMangaForUserAsync(mangaId, updateInfo, user, password).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); } diff --git a/MalApi/UpdateObjectBase.cs b/MalApi/UpdateObjectBase.cs index c49c386..d6e2d4a 100644 --- a/MalApi/UpdateObjectBase.cs +++ b/MalApi/UpdateObjectBase.cs @@ -10,7 +10,7 @@ public class UpdateObjectBase /// /// Generates an XML with the current information stored in the object. XML can later be used to update records on MAL. /// - /// + /// String representation of object-generated XML. public string GenerateXml() { var emptyNamespace = new XmlSerializerNamespaces(); @@ -25,6 +25,7 @@ public string GenerateXml() { xmlSerializer.Serialize(xmlWriter, this, emptyNamespace); xml = strWriter.ToString(); + return xml; } } From 065ffc81fa75ef4f53432166960a0e954d8d144f Mon Sep 17 00:00:00 2001 From: Shavarsh Movsesyan Date: Mon, 13 Nov 2017 00:13:00 +0200 Subject: [PATCH 5/9] Added some tests. Added integration tests for the update functionality. I apologize for the poor execution but my experience with tests is very limtied. There is some strange occurance where some of the tests fail depending on the name of the Initialize function. I guess the name somehow is responsible for the order of execution but I could not find information about it. --- .../GetMangaListForUserTest.cs | 65 +++++++++++++++++ .../UpdateUserAnimeTest.cs | 73 +++++++++++++++++++ .../UpdateUserMangaTest.cs | 73 +++++++++++++++++++ MalApi.UnitTests/MalAppInfoXmlTests.cs | 4 + 4 files changed, 215 insertions(+) create mode 100644 MalApi.IntegrationTests/GetMangaListForUserTest.cs create mode 100644 MalApi.IntegrationTests/UpdateUserAnimeTest.cs create mode 100644 MalApi.IntegrationTests/UpdateUserMangaTest.cs diff --git a/MalApi.IntegrationTests/GetMangaListForUserTest.cs b/MalApi.IntegrationTests/GetMangaListForUserTest.cs new file mode 100644 index 0000000..f9bf7b3 --- /dev/null +++ b/MalApi.IntegrationTests/GetMangaListForUserTest.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MalApi; +using System.Threading.Tasks; +using Xunit; +using System.Threading; + +namespace MalApi.IntegrationTests +{ + // Environment variables in the Initialize method have to be set up properly + // In order for the test to succeed they need to be executed at the same (so the Environment variable can be set and used). + public class GetMangaListForUserTest + { + [Fact] + public static void Initialize() + { + System.Environment.SetEnvironmentVariable("IntegrationTestMalUsername", "username"); + } + + [Fact] + public void GetMangaListForUser() + { + string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); + using (MyAnimeListApi api = new MyAnimeListApi()) + { + MalUserLookupResults userLookup = api.GetMangaListForUser(username); + + Assert.NotEmpty(userLookup.MangaList); + } + } + + [Fact] + public void GetMangaListForUserCanceled() + { + string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); + using (MyAnimeListApi api = new MyAnimeListApi()) + { + CancellationTokenSource tokenSource = new CancellationTokenSource(); + Task userLookupTask = api.GetMangaListForUserAsync(username, tokenSource.Token); + tokenSource.Cancel(); + Assert.Throws(() => userLookupTask.GetAwaiter().GetResult()); + } + } + + [Fact] + public void GetMangaListForNonexistentUserThrowsCorrectException() + { + using (MyAnimeListApi api = new MyAnimeListApi()) + { + Assert.Throws(() => api.GetMangaListForUser("oijsfjisfdjfsdojpfsdp")); + } + } + + [Fact] + public void GetMangaListForNonexistentUserThrowsCorrectExceptionAsync() + { + using (MyAnimeListApi api = new MyAnimeListApi()) + { + Assert.ThrowsAsync(() => api.GetMangaListForUserAsync("oijsfjisfdjfsdojpfsdp")); + } + } + } +} \ No newline at end of file diff --git a/MalApi.IntegrationTests/UpdateUserAnimeTest.cs b/MalApi.IntegrationTests/UpdateUserAnimeTest.cs new file mode 100644 index 0000000..12ddd4e --- /dev/null +++ b/MalApi.IntegrationTests/UpdateUserAnimeTest.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace MalApi.IntegrationTests +{ + // Environment variables in the Initialize method have to be set up properly + // In order for the test to succeed they need to be executed at the same (so the Environment variable can be set and used). + public class UpdateUserAnimeTest + { + [Fact] + public void Initialize() + { + System.Environment.SetEnvironmentVariable("IntegrationTestMalUsername", "user"); + System.Environment.SetEnvironmentVariable("IntegrationTestMalPassword", "password"); + + System.Environment.SetEnvironmentVariable("IntegrationTestAnimeId", "1"); + + System.Environment.SetEnvironmentVariable("IntegrationTestEpisodeNumber", "26"); + System.Environment.SetEnvironmentVariable("IntegrationTestScore", "9"); + System.Environment.SetEnvironmentVariable("IntegrationTestStatus", "2"); + } + + [Fact] + public void UpdateAnimeForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); + string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); + + int animeId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestAnimeId")); + UpdateAnime updateInfo = new UpdateAnime() + { + Episode = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestEpisodeNumber")), + Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), + Status = (AnimeCompletionStatus) int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestStatus")) + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, updateInfo, username, password); + + Assert.Equal("Updated", result); + } + } + + [Fact] + public void GetAnimeListForUserCanceled() + { + string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); + string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); + + int animeId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestAnimeId")); + UpdateAnime updateInfo = new UpdateAnime() + { + Episode = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestEpisodeNumber")), + Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), + Status = (AnimeCompletionStatus)int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestStatus")) + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + CancellationTokenSource tokenSource = new CancellationTokenSource(); + Task userLookupTask = api.UpdateAnimeForUserAsync(animeId, updateInfo, username, password, tokenSource.Token); + tokenSource.Cancel(); + Assert.Throws(() => userLookupTask.GetAwaiter().GetResult()); + } + } + } +} diff --git a/MalApi.IntegrationTests/UpdateUserMangaTest.cs b/MalApi.IntegrationTests/UpdateUserMangaTest.cs new file mode 100644 index 0000000..b5c34eb --- /dev/null +++ b/MalApi.IntegrationTests/UpdateUserMangaTest.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace MalApi.IntegrationTests +{ + // Environment variables in the Initialize method have to be set up properly + // In order for the test to succeed they need to be executed at the same (so the Environment variable can be set and used). + public class UpdateUserMangaTest + { + [Fact] + public void AInitialize() + { + System.Environment.SetEnvironmentVariable("IntegrationTestMalUsername", "user"); + System.Environment.SetEnvironmentVariable("IntegrationTestMalPassword", "password"); + + System.Environment.SetEnvironmentVariable("IntegrationTestMangaId", "952"); + + System.Environment.SetEnvironmentVariable("IntegrationTestChapterNumber", "10"); + System.Environment.SetEnvironmentVariable("IntegrationTestScore", "8"); + System.Environment.SetEnvironmentVariable("IntegrationTestStatus", "1"); + } + + [Fact] + public void UpdateMangaForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); + string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); + + int mangaId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestMangaId")); + UpdateManga updateInfo = new UpdateManga() + { + Chapter = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestChapterNumber")), + Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), + Status = (MangaCompletionStatus)int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestStatus")) + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, updateInfo, username, password); + + Assert.Equal("Updated", result); + } + } + + [Fact] + public void GetMangaListForUserCanceled() + { + string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); + string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); + + int mangaId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestMangaId")); + UpdateManga updateInfo = new UpdateManga() + { + Chapter = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestChapterNumber")), + Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), + Status = (MangaCompletionStatus)int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestStatus")) + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + CancellationTokenSource tokenSource = new CancellationTokenSource(); + Task userLookupTask = api.UpdateMangaForUserAsync(mangaId, updateInfo, username, password, tokenSource.Token); + tokenSource.Cancel(); + Assert.Throws(() => userLookupTask.GetAwaiter().GetResult()); + } + } + } +} diff --git a/MalApi.UnitTests/MalAppInfoXmlTests.cs b/MalApi.UnitTests/MalAppInfoXmlTests.cs index 61359dd..7e03506 100644 --- a/MalApi.UnitTests/MalAppInfoXmlTests.cs +++ b/MalApi.UnitTests/MalAppInfoXmlTests.cs @@ -43,6 +43,8 @@ public void ParseInvalidUserWithXElementTest() { XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_no_such_user.xml")); Assert.Throws(() => MalAppInfoXml.ParseAnimeResults(doc)); + + Assert.Throws(() => MalAppInfoXml.ParseMangaResults(doc)); } [Fact] @@ -59,6 +61,8 @@ public void ParseOldInvalidUserWithXElementTest() { XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_no_such_user_old.xml")); Assert.Throws(() => MalAppInfoXml.ParseAnimeResults(doc)); + + Assert.Throws(() => MalAppInfoXml.ParseMangaResults(doc)); } private void DoAsserts(MalUserLookupResults results) From 73d13737f98d040fccd45af7371bf147f4c0677c Mon Sep 17 00:00:00 2001 From: Shavarsh Movsesyan Date: Wed, 15 Nov 2017 12:43:41 +0200 Subject: [PATCH 6/9] Replaced System.Xml.Serialization with System.Xml.Linq for XML generation. Confirmed Doujin and OEL enum entries. Removed UpdateObjectBase. Put Utf8StringWriter in a separate class. Renamed UpdateAnime and UpdateManga. --- MalApi.Example/Program.cs | 5 +- .../UpdateUserAnimeTest.cs | 4 +- .../UpdateUserMangaTest.cs | 4 +- MalApi.UnitTests/AnimeListCacheTests.cs | 2 +- MalApi.UnitTests/MalAppInfoXmlTests.cs | 10 +- MalApi/Anime/AnimeUpdate.cs | 117 +++++++++ MalApi/Anime/UpdateAnime.cs | 215 ----------------- MalApi/MalAppInfoXml.cs | 211 +++++++---------- MalApi/MalUserLookupResults.cs | 4 +- MalApi/Manga/MangaUpdate.cs | 121 ++++++++++ MalApi/Manga/UpdateManga.cs | 224 ------------------ MalApi/MyAnimeListApi.cs | 12 +- MalApi/UpdateObjectBase.cs | 42 ---- MalApi/Utf8StringWriter.cs | 13 + 14 files changed, 361 insertions(+), 623 deletions(-) create mode 100644 MalApi/Anime/AnimeUpdate.cs delete mode 100644 MalApi/Anime/UpdateAnime.cs create mode 100644 MalApi/Manga/MangaUpdate.cs delete mode 100644 MalApi/Manga/UpdateManga.cs delete mode 100644 MalApi/UpdateObjectBase.cs create mode 100644 MalApi/Utf8StringWriter.cs diff --git a/MalApi.Example/Program.cs b/MalApi.Example/Program.cs index f185b9c..ca071e9 100644 --- a/MalApi.Example/Program.cs +++ b/MalApi.Example/Program.cs @@ -26,16 +26,15 @@ static void Main(string[] args) api.UserAgent = "MalApiExample"; api.TimeoutInMs = 15000; - var animeUpdateInfo = new UpdateAnime() + var animeUpdateInfo = new AnimeUpdate() { Episode = 26, Status = AnimeCompletionStatus.Completed, Score = 9, - DateStart = new DateTime(1999, 01, 02) }; string userUpdateAnime = api.UpdateAnimeForUser(1, animeUpdateInfo, "user", "password"); - var mangaUpdateInfo = new UpdateManga() + var mangaUpdateInfo = new MangaUpdate() { Chapter = 20, Volume = 3, diff --git a/MalApi.IntegrationTests/UpdateUserAnimeTest.cs b/MalApi.IntegrationTests/UpdateUserAnimeTest.cs index 12ddd4e..75d26af 100644 --- a/MalApi.IntegrationTests/UpdateUserAnimeTest.cs +++ b/MalApi.IntegrationTests/UpdateUserAnimeTest.cs @@ -32,7 +32,7 @@ public void UpdateAnimeForUserTest() string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); int animeId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestAnimeId")); - UpdateAnime updateInfo = new UpdateAnime() + AnimeUpdate updateInfo = new AnimeUpdate() { Episode = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestEpisodeNumber")), Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), @@ -54,7 +54,7 @@ public void GetAnimeListForUserCanceled() string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); int animeId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestAnimeId")); - UpdateAnime updateInfo = new UpdateAnime() + AnimeUpdate updateInfo = new AnimeUpdate() { Episode = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestEpisodeNumber")), Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), diff --git a/MalApi.IntegrationTests/UpdateUserMangaTest.cs b/MalApi.IntegrationTests/UpdateUserMangaTest.cs index b5c34eb..2f2f226 100644 --- a/MalApi.IntegrationTests/UpdateUserMangaTest.cs +++ b/MalApi.IntegrationTests/UpdateUserMangaTest.cs @@ -32,7 +32,7 @@ public void UpdateMangaForUserTest() string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); int mangaId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestMangaId")); - UpdateManga updateInfo = new UpdateManga() + MangaUpdate updateInfo = new MangaUpdate() { Chapter = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestChapterNumber")), Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), @@ -54,7 +54,7 @@ public void GetMangaListForUserCanceled() string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); int mangaId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestMangaId")); - UpdateManga updateInfo = new UpdateManga() + MangaUpdate updateInfo = new MangaUpdate() { Chapter = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestChapterNumber")), Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), diff --git a/MalApi.UnitTests/AnimeListCacheTests.cs b/MalApi.UnitTests/AnimeListCacheTests.cs index bb8c629..7232d6d 100644 --- a/MalApi.UnitTests/AnimeListCacheTests.cs +++ b/MalApi.UnitTests/AnimeListCacheTests.cs @@ -15,7 +15,7 @@ public void TestCacheCaseInsensitivity() { using (AnimeListCache cache = new AnimeListCache(expiration: TimeSpan.FromHours(5))) { - cache.PutListForUser("a", new MalUserLookupResults(userId: 5, canonicalUserName: "A", animeList: new List())); + cache.PutListForUser("a", new MalUserLookupResults(userId: 5, canonicalUserName: "A", animeList: new List(), mangaList: new List())); cache.GetListForUser("A", out MalUserLookupResults lookup); Assert.Equal(5, lookup.UserId); } diff --git a/MalApi.UnitTests/MalAppInfoXmlTests.cs b/MalApi.UnitTests/MalAppInfoXmlTests.cs index 7e03506..a6549a1 100644 --- a/MalApi.UnitTests/MalAppInfoXmlTests.cs +++ b/MalApi.UnitTests/MalAppInfoXmlTests.cs @@ -25,7 +25,7 @@ public void ParseWithTextReaderTest() public void ParseWithXElementTest() { XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_clean.xml")); - MalUserLookupResults results = MalAppInfoXml.ParseAnimeResults(doc); + MalUserLookupResults results = MalAppInfoXml.ParseResults(doc); DoAsserts(results); } @@ -42,9 +42,7 @@ public void ParseInvalidUserWithTextReaderTest() public void ParseInvalidUserWithXElementTest() { XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_no_such_user.xml")); - Assert.Throws(() => MalAppInfoXml.ParseAnimeResults(doc)); - - Assert.Throws(() => MalAppInfoXml.ParseMangaResults(doc)); + Assert.Throws(() => MalAppInfoXml.ParseResults(doc)); } [Fact] @@ -60,9 +58,7 @@ public void ParseOldInvalidUserWithTextReaderTest() public void ParseOldInvalidUserWithXElementTest() { XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_no_such_user_old.xml")); - Assert.Throws(() => MalAppInfoXml.ParseAnimeResults(doc)); - - Assert.Throws(() => MalAppInfoXml.ParseMangaResults(doc)); + Assert.Throws(() => MalAppInfoXml.ParseResults(doc)); } private void DoAsserts(MalUserLookupResults results) diff --git a/MalApi/Anime/AnimeUpdate.cs b/MalApi/Anime/AnimeUpdate.cs new file mode 100644 index 0000000..670f5f9 --- /dev/null +++ b/MalApi/Anime/AnimeUpdate.cs @@ -0,0 +1,117 @@ +using System; +using System.Xml; +using System.Xml.Linq; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace MalApi +{ + /// + /// The update object sent to MAL when updating an anime entry. + /// Only specified values will be changed. The rest will remain unchanged. + /// More details: https://myanimelist.net/modules.php?go=api#animevalues + /// + [XmlRoot("entry")] + public class AnimeUpdate + { + [XmlElement("episode")] + public int? Episode { get; set; } = null; + + [XmlElement("status")] + public AnimeCompletionStatus? Status { get; set; } = null; + + [XmlElement("score")] + public int? Score { get; set; } = null; + + [XmlElement("storage_type")] + public int? StorageType { get; set; } = null; + + [XmlElement("storage_value")] + public float? StorageValue { get; set; } = null; + + [XmlElement("times_rewatched")] + public int? TimesRewatched { get; set; } = null; + + [XmlElement("rewatch_value")] + public int? RewatchValue { get; set; } = null; + + [XmlIgnore] + public DateTime? DateStart { get; set; } = null; + + [XmlElement("date_start")] + private string FormattedDateStart + { + get + { + return DateStart?.ToString("MMddyyyy"); + } + set + { + DateStart = DateTime.Parse(value); + } + } + + public DateTime? DateFinish { get; set; } = null; + + [XmlElement("date_finish")] + private string FormattedDateFinish + { + get + { + return DateFinish?.ToString("MMddyyyy"); + } + set + { + DateFinish = DateTime.Parse(value); + } + } + + [XmlElement("priority")] + public int? Priority { get; set; } = null; + + [XmlElement("enable_discussion")] + public int? EnableDiscussion { get; set; } = null; + + [XmlElement("enable_rewatching")] + public int? EnableRewatching { get; set; } = null; + + [XmlElement("comments")] + public string Comments { get; set; } = null; + + [XmlElement("tags")] + public string Tags { get; set; } = null; + + /// + /// Generates an XML with the current information stored in the object. XML can later be used to update records on MAL. + /// + /// String representation of object-generated XML. + public string GenerateXml() + { + XDocument document = new XDocument( + new XDeclaration("1.0", "UTF-8", null), + new XElement("entry", + new XElement("episode", Episode), + new XElement("status", (int?)Status), + new XElement("score", Score), + new XElement("storage_type", StorageType), + new XElement("storage_value", StorageValue), + new XElement("times_rewatched", TimesRewatched), + new XElement("rewatch_value", RewatchValue), + new XElement("date_start", FormattedDateStart), + new XElement("date_finish", FormattedDateFinish), + new XElement("priority", Priority), + new XElement("enable_discussion", EnableDiscussion), + new XElement("enable_rewatching", EnableRewatching), + new XElement("comments", Comments), + new XElement("tags", Tags) + ) + ); + + using (Utf8StringWriter writer = new Utf8StringWriter()) + { + document.Save(writer); + return writer.ToString(); + } + } + } +} diff --git a/MalApi/Anime/UpdateAnime.cs b/MalApi/Anime/UpdateAnime.cs deleted file mode 100644 index 1c21182..0000000 --- a/MalApi/Anime/UpdateAnime.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System; -using System.Xml; -using System.Xml.Schema; -using System.Xml.Serialization; - -namespace MalApi -{ - /// - /// The update object sent to MAL when updating an anime entry. - /// Only specified values will be changed. The rest will remain unchanged. - /// More details: https://myanimelist.net/modules.php?go=api#animevalues - /// - [XmlRoot("entry")] - public class UpdateAnime : UpdateObjectBase, IXmlSerializable - { - [XmlElement("episode")] - public int? Episode { get; set; } = null; - - [XmlElement("status")] - public AnimeCompletionStatus? Status { get; set; } = null; - - [XmlElement("score")] - public int? Score { get; set; } = null; - - [XmlElement("storage_type")] - public int? StorageType { get; set; } = null; - - [XmlElement("storage_value")] - public float? StorageValue { get; set; } = null; - - [XmlElement("times_rewatched")] - public int? TimesRewatched { get; set; } = null; - - [XmlElement("rewatch_value")] - public int? RewatchValue { get; set; } = null; - - [XmlIgnore] - public DateTime? DateStart { get; set; } = null; - - [XmlElement("date_start")] - private string FormattedDateStart - { - get - { - return DateStart?.ToString("MMddyyyy"); - } - set - { - DateStart = DateTime.Parse(value); - } - } - - public DateTime? DateFinish { get; set; } = null; - - [XmlElement("date_finish")] - private string FormattedDateFinish - { - get - { - return DateFinish?.ToString("MMddyyyy"); - } - set - { - DateFinish = DateTime.Parse(value); - } - } - - [XmlElement("priority")] - public int? Priority { get; set; } = null; - - [XmlElement("enable_discussion")] - public int? EnableDiscussion { get; set; } = null; - - [XmlElement("enable_rewatching")] - public int? EnableRewatching { get; set; } = null; - - [XmlElement("comments")] - public string Comments { get; set; } = null; - - [XmlElement("tags")] - public string Tags { get; set; } = null; - - #region IXmlSerializable implementation - - public XmlSchema GetSchema() - { - return null; - } - - // 12.11.17 - MAL API does not return this structure - public void ReadXml(XmlReader reader) - { - throw new NotImplementedException(); - } - - public void WriteXml(XmlWriter writer) - { - // Episode - writer.WriteStartElement("episode"); - if (Episode != null) - { - writer.WriteValue(Episode); - } - writer.WriteEndElement(); - - // Status - writer.WriteStartElement("status"); - if (Status != null) - { - writer.WriteString(Status.Value.ToString().ToLower()); - } - writer.WriteEndElement(); - - // Score - writer.WriteStartElement("score"); - if (Score != null) - { - writer.WriteValue(Score); - } - writer.WriteEndElement(); - - // Storage type - writer.WriteStartElement("storage_type"); - if (StorageType != null) - { - writer.WriteValue(StorageType); - } - writer.WriteEndElement(); - - // Storage value - writer.WriteStartElement("storage_value"); - if (StorageValue != null) - { - writer.WriteValue(StorageValue); - } - writer.WriteEndElement(); - - // Times rewatched - writer.WriteStartElement("times_rewatched"); - if (TimesRewatched != null) - { - writer.WriteValue(TimesRewatched); - } - writer.WriteEndElement(); - - // Rewatch value - writer.WriteStartElement("rewatch_value"); - if (RewatchValue != null) - { - writer.WriteValue(RewatchValue); - } - writer.WriteEndElement(); - - // Date start (formatted) - writer.WriteStartElement("date_start"); - if (FormattedDateStart != null) - { - writer.WriteString(FormattedDateStart); - } - writer.WriteEndElement(); - - // Date finish (formatted) - writer.WriteStartElement("date_finish"); - if (FormattedDateFinish != null) - { - writer.WriteString(FormattedDateFinish); - } - writer.WriteEndElement(); - - // Priority - writer.WriteStartElement("priority"); - if (Priority != null) - { - writer.WriteValue(Priority); - } - writer.WriteEndElement(); - - // Enable discussion - writer.WriteStartElement("enable_discussion"); - if (EnableDiscussion != null) - { - writer.WriteValue(EnableDiscussion); - } - writer.WriteEndElement(); - - // Enable rewatching - writer.WriteStartElement("enable_rewatching"); - if (EnableRewatching != null) - { - writer.WriteValue(EnableRewatching); - } - writer.WriteEndElement(); - - // Enable comments - writer.WriteStartElement("comments"); - if (Comments != null) - - { - writer.WriteString(Comments); - } - writer.WriteEndElement(); - - // Tags - writer.WriteStartElement("tags"); - if (Tags != null) - - { - writer.WriteString(Tags); - } - writer.WriteEndElement(); - } - - #endregion - } -} diff --git a/MalApi/MalAppInfoXml.cs b/MalApi/MalAppInfoXml.cs index b5d4098..125e55e 100644 --- a/MalApi/MalAppInfoXml.cs +++ b/MalApi/MalAppInfoXml.cs @@ -31,15 +31,7 @@ public static async Task ParseAsync(TextReader xmlTextRead // StringReader won't block though. XDocument doc = XDocument.Load(sanitizedXmlTextReader); - IEnumerable anime = doc.Root.Elements("anime").ToList(); - if(anime.Count() != 0) - { - return ParseAnimeResults(doc); - } - else - { - return ParseMangaResults(doc); - } + return ParseResults(doc); } } @@ -112,7 +104,7 @@ private static async Task SanitizeAnimeListXmlAsync(TextReader xml /// /// /// - public static MalUserLookupResults ParseAnimeResults(XDocument doc) + public static MalUserLookupResults ParseResults(XDocument doc) { Logging.Log.Trace("Parsing XML."); @@ -135,163 +127,142 @@ public static MalUserLookupResults ParseAnimeResults(XDocument doc) int userId = GetElementValueInt(myinfo, "user_id"); string canonicalUserName = GetElementValueString(myinfo, "user_name"); - List entries = new List(); + List animeEntries = new List(); + List mangaEntries = new List(); - IEnumerable animes = doc.Root.Elements("anime"); - foreach (XElement anime in animes) + // Anime entries + if (doc.Root.Element("anime") != null) { - int animeId = GetElementValueInt(anime, "series_animedb_id"); - string title = GetElementValueString(anime, "series_title"); - - string synonymList = GetElementValueString(anime, "series_synonyms"); - string[] rawSynonyms = synonymList.Split(SynonymSeparator, StringSplitOptions.RemoveEmptyEntries); - - // filter out synonyms that are the same as the main title - HashSet synonyms = new HashSet(rawSynonyms.Where(synonym => !synonym.Equals(title, StringComparison.Ordinal))); - - int seriesTypeInt = GetElementValueInt(anime, "series_type"); - MalAnimeType seriesType = (MalAnimeType)seriesTypeInt; + IEnumerable animes = doc.Root.Elements("anime"); + foreach (XElement anime in animes) + { + int animeId = GetElementValueInt(anime, "series_animedb_id"); + string title = GetElementValueString(anime, "series_title"); - int numEpisodes = GetElementValueInt(anime, "series_episodes"); + string synonymList = GetElementValueString(anime, "series_synonyms"); + string[] rawSynonyms = synonymList.Split(SynonymSeparator, StringSplitOptions.RemoveEmptyEntries); - int seriesStatusInt = GetElementValueInt(anime, "series_status"); - MalAnimeSeriesStatus seriesStatus = (MalAnimeSeriesStatus)seriesStatusInt; + // filter out synonyms that are the same as the main title + HashSet synonyms = new HashSet(rawSynonyms.Where(synonym => !synonym.Equals(title, StringComparison.Ordinal))); - string seriesStartString = GetElementValueString(anime, "series_start"); - UncertainDate seriesStart = UncertainDate.FromMalDateString(seriesStartString); + int seriesTypeInt = GetElementValueInt(anime, "series_type"); + MalAnimeType seriesType = (MalAnimeType)seriesTypeInt; - string seriesEndString = GetElementValueString(anime, "series_end"); - UncertainDate seriesEnd = UncertainDate.FromMalDateString(seriesEndString); + int numEpisodes = GetElementValueInt(anime, "series_episodes"); - string seriesImage = GetElementValueString(anime, "series_image"); + int seriesStatusInt = GetElementValueInt(anime, "series_status"); + MalAnimeSeriesStatus seriesStatus = (MalAnimeSeriesStatus)seriesStatusInt; - MalAnimeInfoFromUserLookup animeInfo = new MalAnimeInfoFromUserLookup(animeId: animeId, title: title, - type: seriesType, synonyms: synonyms, status: seriesStatus, numEpisodes: numEpisodes, startDate: seriesStart, - endDate: seriesEnd, imageUrl: seriesImage); + string seriesStartString = GetElementValueString(anime, "series_start"); + UncertainDate seriesStart = UncertainDate.FromMalDateString(seriesStartString); + string seriesEndString = GetElementValueString(anime, "series_end"); + UncertainDate seriesEnd = UncertainDate.FromMalDateString(seriesEndString); - int numEpisodesWatched = GetElementValueInt(anime, "my_watched_episodes"); + string seriesImage = GetElementValueString(anime, "series_image"); - string myStartDateString = GetElementValueString(anime, "my_start_date"); - UncertainDate myStartDate = UncertainDate.FromMalDateString(myStartDateString); + MalAnimeInfoFromUserLookup animeInfo = new MalAnimeInfoFromUserLookup(animeId: animeId, title: title, + type: seriesType, synonyms: synonyms, status: seriesStatus, numEpisodes: numEpisodes, startDate: seriesStart, + endDate: seriesEnd, imageUrl: seriesImage); - string myFinishDateString = GetElementValueString(anime, "my_finish_date"); - UncertainDate myFinishDate = UncertainDate.FromMalDateString(myFinishDateString); - decimal rawScore = GetElementValueDecimal(anime, "my_score"); - decimal? myScore = rawScore == 0 ? (decimal?)null : rawScore; + int numEpisodesWatched = GetElementValueInt(anime, "my_watched_episodes"); - int completionStatusInt = GetElementValueInt(anime, "my_status"); - AnimeCompletionStatus completionStatus = (AnimeCompletionStatus)completionStatusInt; + string myStartDateString = GetElementValueString(anime, "my_start_date"); + UncertainDate myStartDate = UncertainDate.FromMalDateString(myStartDateString); - long lastUpdatedUnixTimestamp = GetElementValueLong(anime, "my_last_updated"); - DateTime lastUpdated = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + TimeSpan.FromSeconds(lastUpdatedUnixTimestamp); + string myFinishDateString = GetElementValueString(anime, "my_finish_date"); + UncertainDate myFinishDate = UncertainDate.FromMalDateString(myFinishDateString); - string rawTagsString = GetElementValueString(anime, "my_tags"); - string[] untrimmedTags = rawTagsString.Split(TagSeparator, StringSplitOptions.RemoveEmptyEntries); - List tags = new List(untrimmedTags.Select(tag => tag.Trim())); + decimal rawScore = GetElementValueDecimal(anime, "my_score"); + decimal? myScore = rawScore == 0 ? (decimal?)null : rawScore; - MyAnimeListEntry entry = new MyAnimeListEntry(score: myScore, status: completionStatus, numEpisodesWatched: numEpisodesWatched, - myStartDate: myStartDate, myFinishDate: myFinishDate, myLastUpdate: lastUpdated, animeInfo: animeInfo, tags: tags); + int completionStatusInt = GetElementValueInt(anime, "my_status"); + AnimeCompletionStatus completionStatus = (AnimeCompletionStatus)completionStatusInt; - entries.Add(entry); - } + long lastUpdatedUnixTimestamp = GetElementValueLong(anime, "my_last_updated"); + DateTime lastUpdated = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + TimeSpan.FromSeconds(lastUpdatedUnixTimestamp); - MalUserLookupResults results = new MalUserLookupResults(userId: userId, canonicalUserName: canonicalUserName, animeList: entries); - Logging.Log.Trace("Parsed XML."); - return results; - } + string rawTagsString = GetElementValueString(anime, "my_tags"); + string[] untrimmedTags = rawTagsString.Split(TagSeparator, StringSplitOptions.RemoveEmptyEntries); + List tags = new List(untrimmedTags.Select(tag => tag.Trim())); - public static MalUserLookupResults ParseMangaResults(XDocument doc) - { - Logging.Log.Trace("Parsing XML."); + MyAnimeListEntry entry = new MyAnimeListEntry(score: myScore, status: completionStatus, numEpisodesWatched: numEpisodesWatched, + myStartDate: myStartDate, myFinishDate: myFinishDate, myLastUpdate: lastUpdated, animeInfo: animeInfo, tags: tags); - XElement error = doc.Root.Element("error"); - if (error != null && (string)error == "Invalid username") - { - throw new MalUserNotFoundException("No MAL list exists for this user."); - } - else if (error != null) - { - throw new MalApiException((string)error); + animeEntries.Add(entry); + } } - if (!doc.Root.HasElements) + // Manga entries + if (doc.Root.Element("manga") != null) { - throw new MalUserNotFoundException("No MAL list exists for this user."); - } - XElement myinfo = GetExpectedElement(doc.Root, "myinfo"); - int userId = GetElementValueInt(myinfo, "user_id"); - string canonicalUserName = GetElementValueString(myinfo, "user_name"); - - List entries = new List(); - - IEnumerable mangas = doc.Root.Elements("manga"); - foreach (XElement manga in mangas) - { - int mangaId = GetElementValueInt(manga, "series_mangadb_id"); - string title = GetElementValueString(manga, "series_title"); + IEnumerable mangas = doc.Root.Elements("manga"); + foreach (XElement manga in mangas) + { + int mangaId = GetElementValueInt(manga, "series_mangadb_id"); + string title = GetElementValueString(manga, "series_title"); - string synonymList = GetElementValueString(manga, "series_synonyms"); - string[] rawSynonyms = synonymList.Split(SynonymSeparator, StringSplitOptions.RemoveEmptyEntries); + string synonymList = GetElementValueString(manga, "series_synonyms"); + string[] rawSynonyms = synonymList.Split(SynonymSeparator, StringSplitOptions.RemoveEmptyEntries); - // filter out synonyms that are the same as the main title - HashSet synonyms = new HashSet(rawSynonyms.Where(synonym => !synonym.Equals(title, StringComparison.Ordinal))); + // filter out synonyms that are the same as the main title + HashSet synonyms = new HashSet(rawSynonyms.Where(synonym => !synonym.Equals(title, StringComparison.Ordinal))); - int seriesTypeInt = GetElementValueInt(manga, "series_type"); - MalMangaType seriesType = (MalMangaType)seriesTypeInt; + int seriesTypeInt = GetElementValueInt(manga, "series_type"); + MalMangaType seriesType = (MalMangaType)seriesTypeInt; - int numChapters = GetElementValueInt(manga, "series_chapters"); + int numChapters = GetElementValueInt(manga, "series_chapters"); - int numVolumes = GetElementValueInt(manga, "series_volumes"); + int numVolumes = GetElementValueInt(manga, "series_volumes"); - int seriesStatusInt = GetElementValueInt(manga, "series_status"); - MalMangaSeriesStatus seriesStatus = (MalMangaSeriesStatus)seriesStatusInt; + int seriesStatusInt = GetElementValueInt(manga, "series_status"); + MalMangaSeriesStatus seriesStatus = (MalMangaSeriesStatus)seriesStatusInt; - string seriesStartString = GetElementValueString(manga, "series_start"); - UncertainDate seriesStart = UncertainDate.FromMalDateString(seriesStartString); + string seriesStartString = GetElementValueString(manga, "series_start"); + UncertainDate seriesStart = UncertainDate.FromMalDateString(seriesStartString); - string seriesEndString = GetElementValueString(manga, "series_end"); - UncertainDate seriesEnd = UncertainDate.FromMalDateString(seriesEndString); + string seriesEndString = GetElementValueString(manga, "series_end"); + UncertainDate seriesEnd = UncertainDate.FromMalDateString(seriesEndString); - string seriesImage = GetElementValueString(manga, "series_image"); + string seriesImage = GetElementValueString(manga, "series_image"); - MalMangaInfoFromUserLookup mangaInfo = new MalMangaInfoFromUserLookup(mangaId: mangaId, title: title, - type: seriesType, synonyms: synonyms, status: seriesStatus, numChapters: numChapters, numVolumes: numVolumes, startDate: seriesStart, - endDate: seriesEnd, imageUrl: seriesImage); + MalMangaInfoFromUserLookup mangaInfo = new MalMangaInfoFromUserLookup(mangaId: mangaId, title: title, + type: seriesType, synonyms: synonyms, status: seriesStatus, numChapters: numChapters, numVolumes: numVolumes, startDate: seriesStart, + endDate: seriesEnd, imageUrl: seriesImage); - int numChaptersRead = GetElementValueInt(manga, "my_read_chapters"); + int numChaptersRead = GetElementValueInt(manga, "my_read_chapters"); - int numVolumesRead = GetElementValueInt(manga, "my_read_volumes"); + int numVolumesRead = GetElementValueInt(manga, "my_read_volumes"); - string myStartDateString = GetElementValueString(manga, "my_start_date"); - UncertainDate myStartDate = UncertainDate.FromMalDateString(myStartDateString); + string myStartDateString = GetElementValueString(manga, "my_start_date"); + UncertainDate myStartDate = UncertainDate.FromMalDateString(myStartDateString); - string myFinishDateString = GetElementValueString(manga, "my_finish_date"); - UncertainDate myFinishDate = UncertainDate.FromMalDateString(myFinishDateString); + string myFinishDateString = GetElementValueString(manga, "my_finish_date"); + UncertainDate myFinishDate = UncertainDate.FromMalDateString(myFinishDateString); - decimal rawScore = GetElementValueDecimal(manga, "my_score"); - decimal? myScore = rawScore == 0 ? (decimal?)null : rawScore; + decimal rawScore = GetElementValueDecimal(manga, "my_score"); + decimal? myScore = rawScore == 0 ? (decimal?)null : rawScore; - int completionStatusInt = GetElementValueInt(manga, "my_status"); - MangaCompletionStatus completionStatus = (MangaCompletionStatus)completionStatusInt; + int completionStatusInt = GetElementValueInt(manga, "my_status"); + MangaCompletionStatus completionStatus = (MangaCompletionStatus)completionStatusInt; - long lastUpdatedUnixTimestamp = GetElementValueLong(manga, "my_last_updated"); - DateTime lastUpdated = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + TimeSpan.FromSeconds(lastUpdatedUnixTimestamp); + long lastUpdatedUnixTimestamp = GetElementValueLong(manga, "my_last_updated"); + DateTime lastUpdated = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) + TimeSpan.FromSeconds(lastUpdatedUnixTimestamp); - string rawTagsString = GetElementValueString(manga, "my_tags"); - string[] untrimmedTags = rawTagsString.Split(TagSeparator, StringSplitOptions.RemoveEmptyEntries); - List tags = new List(untrimmedTags.Select(tag => tag.Trim())); + string rawTagsString = GetElementValueString(manga, "my_tags"); + string[] untrimmedTags = rawTagsString.Split(TagSeparator, StringSplitOptions.RemoveEmptyEntries); + List tags = new List(untrimmedTags.Select(tag => tag.Trim())); - MyMangaListEntry entry = new MyMangaListEntry(score: myScore, status: completionStatus, numChaptersRead: numChaptersRead, numVolumesRead: numVolumesRead, - myStartDate: myStartDate, myFinishDate: myFinishDate, myLastUpdate: lastUpdated, mangaInfo: mangaInfo, tags: tags); + MyMangaListEntry entry = new MyMangaListEntry(score: myScore, status: completionStatus, numChaptersRead: numChaptersRead, numVolumesRead: numVolumesRead, + myStartDate: myStartDate, myFinishDate: myFinishDate, myLastUpdate: lastUpdated, mangaInfo: mangaInfo, tags: tags); - entries.Add(entry); + mangaEntries.Add(entry); + } } - - MalUserLookupResults results = new MalUserLookupResults(userId: userId, canonicalUserName: canonicalUserName, mangaList: entries); + MalUserLookupResults results = new MalUserLookupResults(userId: userId, canonicalUserName: canonicalUserName, animeList: animeEntries, mangaList: mangaEntries); Logging.Log.Trace("Parsed XML."); return results; } diff --git a/MalApi/MalUserLookupResults.cs b/MalApi/MalUserLookupResults.cs index 8b8245e..dff2fe7 100644 --- a/MalApi/MalUserLookupResults.cs +++ b/MalApi/MalUserLookupResults.cs @@ -16,6 +16,7 @@ public class MalUserLookupResults /// public string CanonicalUserName { get; private set; } + // Left for backwards compatibility public MalUserLookupResults(int userId, string canonicalUserName, ICollection animeList) { UserId = userId; @@ -23,10 +24,11 @@ public MalUserLookupResults(int userId, string canonicalUserName, ICollection mangaList) + public MalUserLookupResults(int userId, string canonicalUserName, ICollection animeList, ICollection mangaList) { UserId = userId; CanonicalUserName = canonicalUserName; + AnimeList = animeList; MangaList = mangaList; } } diff --git a/MalApi/Manga/MangaUpdate.cs b/MalApi/Manga/MangaUpdate.cs new file mode 100644 index 0000000..bdc684e --- /dev/null +++ b/MalApi/Manga/MangaUpdate.cs @@ -0,0 +1,121 @@ +using System; +using System.Xml; +using System.Xml.Linq; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace MalApi +{ + /// + /// The update object sent to MAL when updating a manga entry. + /// Only specified values will be changed. The rest will remain unchanged. + /// More details: https://myanimelist.net/modules.php?go=api#mangavalues + /// + [XmlRoot("entry")] + public class MangaUpdate + { + [XmlElement("chapter")] + public int? Chapter { get; set; } = null; + + [XmlElement("volume")] + public int? Volume { get; set; } = null; + + [XmlElement("status")] + public MangaCompletionStatus? Status { get; set; } = null; + + [XmlElement("score")] + public int? Score { get; set; } = null; + + [XmlElement("times_reread")] + public int? TimesReread { get; set; } = null; + + [XmlElement("reread_value")] + public int? RereadValue { get; set; } = null; + + [XmlIgnore] + public DateTime? DateStart { get; set; } = null; + + [XmlElement("date_start")] + private string FormattedDateStart + { + get + { + return DateStart?.ToString("MMddyyyy"); + } + set + { + DateStart = DateTime.Parse(value); + } + } + + public DateTime? DateFinish { get; set; } = null; + + [XmlElement("date_finish")] + private string FormattedDateFinish + { + get + { + return DateFinish?.ToString("MMddyyyy"); + } + set + { + DateFinish = DateTime.Parse(value); + } + } + + [XmlElement("priority")] + public int? Priority { get; set; } = null; + + [XmlElement("enable_discussion")] + public int? EnableDiscussion { get; set; } = null; + + [XmlElement("enable_rereading")] + public int? EnableRereading { get; set; } = null; + + [XmlElement("comments")] + public string Comments { get; set; } = null; + + [XmlElement("scan_group")] + public string ScanGroup { get; set; } = null; + + [XmlElement("tags")] + public string Tags { get; set; } = null; + + [XmlElement("retail_volumes")] + public int? RetailVolumes { get; set; } = null; + + /// + /// Generates an XML with the current information stored in the object. XML can later be used to update records on MAL. + /// + /// String representation of object-generated XML. + public string GenerateXml() + { + XDocument document = new XDocument( + new XDeclaration("1.0", "UTF-8", null), + new XElement("entry", + new XElement("chapter", Chapter), + new XElement("volume", Volume), + new XElement("status", (int?)Status), + new XElement("score", Score), + new XElement("times_reread", TimesReread), + new XElement("reread_value", RereadValue), + new XElement("date_start", FormattedDateStart), + new XElement("date_finish", FormattedDateFinish), + new XElement("priority", Priority), + new XElement("enable_discussion", EnableDiscussion), + new XElement("enable_rereading", EnableRereading), + new XElement("comments", Comments), + new XElement("scan_group", ScanGroup), + new XElement("tags", Tags), + new XElement("retail_volumes", RetailVolumes) + ) + ); + + using (Utf8StringWriter writer = new Utf8StringWriter()) + { + document.Save(writer); + return writer.ToString(); + } + } + } +} diff --git a/MalApi/Manga/UpdateManga.cs b/MalApi/Manga/UpdateManga.cs deleted file mode 100644 index b4ddfbf..0000000 --- a/MalApi/Manga/UpdateManga.cs +++ /dev/null @@ -1,224 +0,0 @@ -using System; -using System.Xml; -using System.Xml.Schema; -using System.Xml.Serialization; - -namespace MalApi -{ - /// - /// The update object sent to MAL when updating a manga entry. - /// Only specified values will be changed. The rest will remain unchanged. - /// More details: https://myanimelist.net/modules.php?go=api#mangavalues - /// - [XmlRoot("entry")] - public class UpdateManga : UpdateObjectBase, IXmlSerializable - { - [XmlElement("chapter")] - public int? Chapter { get; set; } = null; - - [XmlElement("volume")] - public int? Volume { get; set; } = null; - - [XmlElement("status")] - public MangaCompletionStatus? Status { get; set; } = null; - - [XmlElement("score")] - public int? Score { get; set; } = null; - - [XmlElement("times_reread")] - public int? TimesReread { get; set; } = null; - - [XmlElement("reread_value")] - public int? RereadValue { get; set; } = null; - - [XmlIgnore] - public DateTime? DateStart { get; set; } = null; - - [XmlElement("date_start")] - private string FormattedDateStart - { - get - { - return DateStart?.ToString("MMddyyyy"); - } - set - { - DateStart = DateTime.Parse(value); - } - } - - public DateTime? DateFinish { get; set; } = null; - - [XmlElement("date_finish")] - private string FormattedDateFinish - { - get - { - return DateFinish?.ToString("MMddyyyy"); - } - set - { - DateFinish = DateTime.Parse(value); - } - } - - [XmlElement("priority")] - public int? Priority { get; set; } = null; - - [XmlElement("enable_discussion")] - public int? EnableDiscussion { get; set; } = null; - - [XmlElement("enable_rereading")] - public int? EnableRereading { get; set; } = null; - - [XmlElement("comments")] - public string Comments { get; set; } = null; - - [XmlElement("scan_group")] - public string ScanGroup { get; set; } = null; - - [XmlElement("tags")] - public string Tags { get; set; } = null; - - [XmlElement("retail_volumes")] - public int? RetailVolumes { get; set; } = null; - - #region IXmlSerializable implementation - - public XmlSchema GetSchema() - { - return null; - } - - // 12.11.17 - MAL API does not return this structure - public void ReadXml(XmlReader reader) - { - throw new NotImplementedException(); - } - - public void WriteXml(XmlWriter writer) - { - // Episode - writer.WriteStartElement("chapter"); - if (Chapter != null) - { - writer.WriteValue(Chapter); - } - writer.WriteEndElement(); - - // Volume - writer.WriteStartElement("volume"); - if (Volume != null) - { - writer.WriteValue(Volume); - } - writer.WriteEndElement(); - - // Status - writer.WriteStartElement("status"); - if (Status != null) - { - writer.WriteString(Status.Value.ToString().ToLower()); - } - writer.WriteEndElement(); - - // Score - writer.WriteStartElement("score"); - if (Score != null) - { - writer.WriteValue(Score); - } - writer.WriteEndElement(); - - // Times reread - writer.WriteStartElement("times_reread"); - if (TimesReread != null) - { - writer.WriteValue(TimesReread); - } - writer.WriteEndElement(); - - // Reread value - writer.WriteStartElement("reread_value"); - if (RereadValue != null) - { - writer.WriteValue(RereadValue); - } - writer.WriteEndElement(); - - // Date start (formatted) - writer.WriteStartElement("date_start"); - if (FormattedDateStart != null) - { - writer.WriteString(FormattedDateStart); - } - writer.WriteEndElement(); - - // Date finish (formatted) - writer.WriteStartElement("date_finish"); - if (FormattedDateFinish != null) - { - writer.WriteString(FormattedDateFinish); - } - writer.WriteEndElement(); - - // Priority - writer.WriteStartElement("priority"); - if (Priority != null) - { - writer.WriteValue(Priority); - } - writer.WriteEndElement(); - - // Enable discussion - writer.WriteStartElement("enable_discussion"); - if (EnableDiscussion != null) - { - writer.WriteValue(EnableDiscussion); - } - writer.WriteEndElement(); - - // Enable rereading - writer.WriteStartElement("enable_rereading"); - if (EnableRereading != null) - { - writer.WriteValue(EnableRereading); - } - writer.WriteEndElement(); - - // Comments - writer.WriteStartElement("comments"); - if (Comments != null) - { - writer.WriteString(Comments); - } - writer.WriteEndElement(); - - // Scan group - writer.WriteStartElement("scan_group"); - if (ScanGroup != null) - { - writer.WriteString(ScanGroup); - } - writer.WriteEndElement(); - - // Tags - writer.WriteStartElement("tags"); - if (Tags != null) - { - writer.WriteString(Tags); - } - writer.WriteEndElement(); - - // Retail volumes - writer.WriteStartElement("retail_volumes"); - if (RetailVolumes != null) - { - writer.WriteValue(RetailVolumes); - } - writer.WriteEndElement(); - } - - #endregion - } -} diff --git a/MalApi/MyAnimeListApi.cs b/MalApi/MyAnimeListApi.cs index 2766a8a..f2f7cd4 100644 --- a/MalApi/MyAnimeListApi.cs +++ b/MalApi/MyAnimeListApi.cs @@ -218,7 +218,7 @@ public Task GetAnimeListForUserAsync(string user) /// /// /// - public Task UpdateAnimeForUserAsync(int animeId, UpdateAnime updateInfo, string user, string password) + public Task UpdateAnimeForUserAsync(int animeId, AnimeUpdate updateInfo, string user, string password) { return UpdateAnimeForUserAsync(animeId, updateInfo, user, password, CancellationToken.None); } @@ -243,7 +243,7 @@ public Task GetMangaListForUserAsync(string user) /// /// /// - public Task UpdateMangaForUserAsync(int mangaId, UpdateManga updateInfo, string user, string password) + public Task UpdateMangaForUserAsync(int mangaId, MangaUpdate updateInfo, string user, string password) { return UpdateMangaForUserAsync(mangaId, updateInfo, user, password, CancellationToken.None); } @@ -306,7 +306,7 @@ public async Task GetAnimeListForUserAsync(string user, Ca /// MAL username /// MAL password /// - public async Task UpdateAnimeForUserAsync(int animeId, UpdateAnime updateInfo, string user, string password, CancellationToken cancellationToken) + public async Task UpdateAnimeForUserAsync(int animeId, AnimeUpdate updateInfo, string user, string password, CancellationToken cancellationToken) { const string malAnimeUpdateUriFormatString = "https://myanimelist.net/api/animelist/update/{0}.xml"; @@ -400,7 +400,7 @@ public async Task GetMangaListForUserAsync(string user, /// MAL user /// MAL password /// - public async Task UpdateMangaForUserAsync(int mangaId, UpdateManga updateInfo, string user, string password, CancellationToken cancellationToken) + public async Task UpdateMangaForUserAsync(int mangaId, MangaUpdate updateInfo, string user, string password, CancellationToken cancellationToken) { const string malMangaUpdateUriFormatString = "https://myanimelist.net/api/mangalist/update/{0}.xml"; @@ -456,7 +456,7 @@ public MalUserLookupResults GetAnimeListForUser(string user) /// Password /// base64 encrypted username and password /// - public string UpdateAnimeForUser(int animeId, UpdateAnime updateInfo, string user, string password) + public string UpdateAnimeForUser(int animeId, AnimeUpdate updateInfo, string user, string password) { return UpdateAnimeForUserAsync(animeId, updateInfo, user, password).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); } @@ -482,7 +482,7 @@ public MalUserLookupResults GetMangaListForUser(string user) /// Password /// base64 encrypted username and password /// - public string UpdateMangaForUser(int mangaId, UpdateManga updateInfo, string user, string password) + public string UpdateMangaForUser(int mangaId, MangaUpdate updateInfo, string user, string password) { return UpdateMangaForUserAsync(mangaId, updateInfo, user, password).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); } diff --git a/MalApi/UpdateObjectBase.cs b/MalApi/UpdateObjectBase.cs deleted file mode 100644 index d6e2d4a..0000000 --- a/MalApi/UpdateObjectBase.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.IO; -using System.Text; -using System.Xml; -using System.Xml.Serialization; - -namespace MalApi -{ - public class UpdateObjectBase - { - /// - /// Generates an XML with the current information stored in the object. XML can later be used to update records on MAL. - /// - /// String representation of object-generated XML. - public string GenerateXml() - { - var emptyNamespace = new XmlSerializerNamespaces(); - emptyNamespace.Add("", ""); - - XmlSerializer xmlSerializer = new XmlSerializer(this.GetType()); - var xml = string.Empty; - - using (var strWriter = new Utf8StringWriter()) - { - using (XmlWriter xmlWriter = XmlWriter.Create(strWriter)) - { - xmlSerializer.Serialize(xmlWriter, this, emptyNamespace); - xml = strWriter.ToString(); - - return xml; - } - } - } - - /// - /// Used to override the encoding of the writer to UTF-8. - /// - private class Utf8StringWriter : StringWriter - { - public override Encoding Encoding => Encoding.UTF8; - } - } -} diff --git a/MalApi/Utf8StringWriter.cs b/MalApi/Utf8StringWriter.cs new file mode 100644 index 0000000..6d42349 --- /dev/null +++ b/MalApi/Utf8StringWriter.cs @@ -0,0 +1,13 @@ +using System.IO; +using System.Text; + +namespace MalApi +{ + /// + /// Used to override the encoding of the writer to UTF-8. + /// + public class Utf8StringWriter : StringWriter + { + public override Encoding Encoding => Encoding.UTF8; + } +} From fbafe1592a7f9568058b98316e038e46da9c6605 Mon Sep 17 00:00:00 2001 From: Shavarsh Movsesyan Date: Wed, 15 Nov 2017 12:56:58 +0200 Subject: [PATCH 7/9] Missed to remove the comments. --- MalApi/Manga/MalMangaType.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MalApi/Manga/MalMangaType.cs b/MalApi/Manga/MalMangaType.cs index fcce6a5..43bbe46 100644 --- a/MalApi/Manga/MalMangaType.cs +++ b/MalApi/Manga/MalMangaType.cs @@ -6,9 +6,9 @@ public enum MalMangaType Manga = 1, Novel = 2, OneShot = 3, - Doujin = 4, // not sure + Doujin = 4, Manwha = 5, Manhua = 6, - OEL = 7 // not sure + OEL = 7 } } \ No newline at end of file From 97c9dc1be7d7dc178fa262c804be82f27fe800ff Mon Sep 17 00:00:00 2001 From: Shavarsh Movsesyan Date: Sat, 20 Jan 2018 15:48:09 +0200 Subject: [PATCH 8/9] Added integration test for anime and manga updates (all the values and individual test for each property). Added wrong username tests. Added HtmlAgilityPack for use in tests. Added HTML scraping tests for anime and manga. Various bug fixes. Changed the readme to include set up information for environment variables. Added/renamed embedded XML files used for unit tests. Commented out ScanGroup/scan_group property for manga since there doesn't seem to be a way to confirm that it's actually doing anything. --- .../GetMangaListForUserTest.cs | 10 +- .../UpdateUserAnimeTest.cs | 958 +++++++++++++++++- .../UpdateUserMangaTest.cs | 875 +++++++++++++++- MalApi.IntegrationTests/readme.txt | 13 +- MalApi.UnitTests/Cowboy_Bebop.htm | 1 + MalApi.UnitTests/MalApi.UnitTests.csproj | 18 +- MalApi.UnitTests/MalAppInfoXmlTests.cs | 75 +- MalApi.UnitTests/Monster.htm | 1 + MalApi.UnitTests/MyAnimeListApiTests.cs | 95 ++ MalApi.UnitTests/{test.xml => test_anime.xml} | 0 .../{test_clean.xml => test_anime_clean.xml} | 0 MalApi.UnitTests/test_manga.xml | 151 +++ MalApi.UnitTests/test_manga_clean.xml | 151 +++ MalApi/Anime/AnimeUpdate.cs | 28 +- MalApi/MalApi.csproj | 1 + MalApi/Manga/MangaUpdate.cs | 30 +- MalApi/MyAnimeListApi.cs | 515 +++++++++- 17 files changed, 2822 insertions(+), 100 deletions(-) create mode 100644 MalApi.UnitTests/Cowboy_Bebop.htm create mode 100644 MalApi.UnitTests/Monster.htm rename MalApi.UnitTests/{test.xml => test_anime.xml} (100%) rename MalApi.UnitTests/{test_clean.xml => test_anime_clean.xml} (100%) create mode 100644 MalApi.UnitTests/test_manga.xml create mode 100644 MalApi.UnitTests/test_manga_clean.xml diff --git a/MalApi.IntegrationTests/GetMangaListForUserTest.cs b/MalApi.IntegrationTests/GetMangaListForUserTest.cs index f9bf7b3..d2cf02b 100644 --- a/MalApi.IntegrationTests/GetMangaListForUserTest.cs +++ b/MalApi.IntegrationTests/GetMangaListForUserTest.cs @@ -13,16 +13,10 @@ namespace MalApi.IntegrationTests // In order for the test to succeed they need to be executed at the same (so the Environment variable can be set and used). public class GetMangaListForUserTest { - [Fact] - public static void Initialize() - { - System.Environment.SetEnvironmentVariable("IntegrationTestMalUsername", "username"); - } - [Fact] public void GetMangaListForUser() { - string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); + string username = "naps250"; using (MyAnimeListApi api = new MyAnimeListApi()) { MalUserLookupResults userLookup = api.GetMangaListForUser(username); @@ -34,7 +28,7 @@ public void GetMangaListForUser() [Fact] public void GetMangaListForUserCanceled() { - string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); + string username = "naps250"; using (MyAnimeListApi api = new MyAnimeListApi()) { CancellationTokenSource tokenSource = new CancellationTokenSource(); diff --git a/MalApi.IntegrationTests/UpdateUserAnimeTest.cs b/MalApi.IntegrationTests/UpdateUserAnimeTest.cs index 75d26af..4b70504 100644 --- a/MalApi.IntegrationTests/UpdateUserAnimeTest.cs +++ b/MalApi.IntegrationTests/UpdateUserAnimeTest.cs @@ -13,52 +13,921 @@ namespace MalApi.IntegrationTests public class UpdateUserAnimeTest { [Fact] - public void Initialize() + public void UpdateAnimeForUserTest() { - System.Environment.SetEnvironmentVariable("IntegrationTestMalUsername", "user"); - System.Environment.SetEnvironmentVariable("IntegrationTestMalPassword", "password"); + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate baseInfo = new AnimeUpdate() + { + Episode = 1, + Status = AnimeCompletionStatus.Watching, + Score = 3, + StorageType = 3, // VHS + StorageValue = 1, + TimesRewatched = 1, + RewatchValue = 2, // low + DateStart = new DateTime(2017, 10, 1), + DateFinish = new DateTime(2017, 10, 5), + Priority = 0, // low + EnableDiscussion = 0, + EnableRewatching = 0, + Comments = "base comment,base comment 2", + Tags = "test base tag, test base tag 2" + }; + + AnimeUpdate updateInfo = new AnimeUpdate() + { + Episode = 26, + Status = AnimeCompletionStatus.Completed, + Score = 8, + StorageType = 5, // VHS + StorageValue = 123, + TimesRewatched = 2, + RewatchValue = 4, // high + DateStart = new DateTime(2017, 12, 10), + DateFinish = new DateTime(2017, 12, 15), + Priority = 1, // medium + EnableDiscussion = 1, + EnableRewatching = 1, + Comments = "test updated comment, test updated comment2", + Tags = "test updated tag, test updated tag 2" + }; - System.Environment.SetEnvironmentVariable("IntegrationTestAnimeId", "1"); + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, baseInfo, username, password); + Assert.Equal("Updated", result); - System.Environment.SetEnvironmentVariable("IntegrationTestEpisodeNumber", "26"); - System.Environment.SetEnvironmentVariable("IntegrationTestScore", "9"); - System.Environment.SetEnvironmentVariable("IntegrationTestStatus", "2"); + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(baseInfo.Episode, baseReults.Episode); + Assert.Equal(baseInfo.Status, baseReults.Status); + Assert.Equal(baseInfo.Score, baseReults.Score); + Assert.Equal(baseInfo.StorageType, baseReults.StorageType); + Assert.Equal(baseInfo.StorageValue, baseReults.StorageValue); + Assert.Equal(baseInfo.TimesRewatched, baseReults.TimesRewatched); + Assert.Equal(baseInfo.RewatchValue, baseReults.RewatchValue); + Assert.Equal(baseInfo.DateStart, baseReults.DateStart); + Assert.Equal(baseInfo.DateFinish, baseReults.DateFinish); + Assert.Equal(baseInfo.Priority, baseReults.Priority); + Assert.Equal(baseInfo.EnableDiscussion, baseReults.EnableDiscussion); + Assert.Equal(baseInfo.EnableRewatching, baseReults.EnableRewatching); + Assert.Equal(baseInfo.Comments, baseReults.Comments); + Assert.Equal(baseInfo.Tags, baseReults.Tags); + + result = api.UpdateAnimeForUser(animeId, updateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(updateInfo.Episode, updatedResults.Episode); + Assert.Equal(updateInfo.Status, updatedResults.Status); + Assert.Equal(updateInfo.Score, updatedResults.Score); + Assert.Equal(updateInfo.StorageType, updatedResults.StorageType); + Assert.Equal(updateInfo.StorageValue, updatedResults.StorageValue); + Assert.Equal(updateInfo.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(updateInfo.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(updateInfo.DateStart, updatedResults.DateStart); + Assert.Equal(updateInfo.DateFinish, updatedResults.DateFinish); + Assert.Equal(updateInfo.Priority, updatedResults.Priority); + Assert.Equal(updateInfo.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(updateInfo.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(updateInfo.Comments, updatedResults.Comments); + Assert.Equal(updateInfo.Tags, updatedResults.Tags); + + // Assert all values have been changed + Assert.NotEqual(baseReults.Episode, updatedResults.Episode); + Assert.NotEqual(baseReults.Status, updatedResults.Status); + Assert.NotEqual(baseReults.Score, updatedResults.Score); + Assert.NotEqual(baseReults.StorageType, updatedResults.StorageType); + Assert.NotEqual(baseReults.StorageValue, updatedResults.StorageValue); + Assert.NotEqual(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.NotEqual(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); + Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); + Assert.NotEqual(baseReults.Priority, updatedResults.Priority); + Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.NotEqual(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.NotEqual(baseReults.Comments, updatedResults.Comments); + Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + } } [Fact] - public void UpdateAnimeForUserTest() + public void UpdateAnimeEpisodeForUserTest() { - string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); - string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); - int animeId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestAnimeId")); - AnimeUpdate updateInfo = new AnimeUpdate() + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + Episode = 1 + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + Episode = 26 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Episode, baseReults.Episode); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Episode, updatedResults.Episode); + + // Assert that only the episode has been changed + Assert.NotEqual(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeStatusForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + Status = AnimeCompletionStatus.Watching + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + Status = AnimeCompletionStatus.Completed + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Status, baseReults.Status); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Status, updatedResults.Status); + + // Assert that only the status has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.NotEqual(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeScoreForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + Score = 3 + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + Score = 8 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Score, baseReults.Score); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Score, updatedResults.Score); + + // Assert that only the score has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.NotEqual(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeStorageTypeForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + StorageType = 3 // VHS + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + StorageType = 5 // VHS + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.StorageType, baseReults.StorageType); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.StorageType, updatedResults.StorageType); + + // Assert that only the storage type has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.NotEqual(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeStorageValueForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + StorageValue = 1 + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + StorageValue = 123 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.StorageValue, baseReults.StorageValue); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.StorageValue, updatedResults.StorageValue); + + // Assert that only the storage value has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.NotEqual(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeTimesRewatchedForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + TimesRewatched = 1 + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + TimesRewatched = 2 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.TimesRewatched, baseReults.TimesRewatched); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.TimesRewatched, updatedResults.TimesRewatched); + + // Assert that only the times rewatched has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.NotEqual(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeRewatchValueForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + RewatchValue = 2 // low + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + RewatchValue = 4 // high + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.RewatchValue, baseReults.RewatchValue); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.RewatchValue, updatedResults.RewatchValue); + + // Assert that only the rewatch value has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.NotEqual(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeDateStartForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + DateStart = new DateTime(2017, 10, 1) + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + DateStart = new DateTime(2017, 12, 10) + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.DateStart, baseReults.DateStart); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.DateStart, updatedResults.DateStart); + + // Assert that only the date start has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeDateFinishForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + DateFinish = new DateTime(2017, 10, 5) + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() { - Episode = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestEpisodeNumber")), - Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), - Status = (AnimeCompletionStatus) int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestStatus")) + DateFinish = new DateTime(2017, 12, 15) }; using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, updateInfo, username, password); + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.DateFinish, baseReults.DateFinish); + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.DateFinish, updatedResults.DateFinish); + + // Assert that only the date finish has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimePriorityForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + Priority = 0 // low + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + Priority = 1 // medium + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Priority, baseReults.Priority); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Priority, updatedResults.Priority); + + // Assert that only the priority has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.NotEqual(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeEnableDiscussionForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + EnableDiscussion = 0 + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + EnableDiscussion = 1 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.EnableDiscussion, baseReults.EnableDiscussion); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.EnableDiscussion, updatedResults.EnableDiscussion); + + // Assert that only the enable discussion has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeEnableRewatchingForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + EnableRewatching = 0 + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + EnableRewatching = 1 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.EnableRewatching, baseReults.EnableRewatching); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.EnableRewatching, updatedResults.EnableRewatching); + + // Assert that only the enable rewatching has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.NotEqual(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeCommentsForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + Comments = "base comment,base comment 2" + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + Comments = "test updated comment, test updated comment2" + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Comments, baseReults.Comments); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Comments, updatedResults.Comments); + + // Assert that only the comments has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.NotEqual(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateAnimeTagsForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + Tags = "test base tag, test base tag 2" + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + Tags = "test updated tag, test updated tag 2" + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Tags, baseReults.Tags); + + + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Tags, updatedResults.Tags); + + // Assert that only the tags has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.NotEqual(baseReults.Tags, updatedResults.Tags); } } [Fact] public void GetAnimeListForUserCanceled() { - string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); - string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; - int animeId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestAnimeId")); AnimeUpdate updateInfo = new AnimeUpdate() { - Episode = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestEpisodeNumber")), - Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), - Status = (AnimeCompletionStatus)int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestStatus")) + Episode = 26, + Status = AnimeCompletionStatus.Completed, + Score = 8, + StorageType = 5, // VHS + StorageValue = 123, + TimesRewatched = 2, + RewatchValue = 4, // high + DateStart = new DateTime(2017, 12, 10), + DateFinish = new DateTime(2017, 12, 15), + Priority = 1, // medium + EnableDiscussion = 1, + EnableRewatching = 1, + Comments = "test updated comment, test updated comment2", + Tags = "test updated tag, test updated tag 2" }; using (MyAnimeListApi api = new MyAnimeListApi()) @@ -69,5 +938,50 @@ public void GetAnimeListForUserCanceled() Assert.Throws(() => userLookupTask.GetAwaiter().GetResult()); } } + + [Fact] + public void IncorrectUsernameAnimeEpisodeUpdateTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + username += "test"; + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Cowboy Bebop + int animeId = 1; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + Episode = 1 + }; + + AnimeUpdate partialUpdateInfo = new AnimeUpdate() + { + Episode = 26 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + try + { + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + + } + catch (Exception ex) + { + Assert.Equal(typeof(MalApiRequestException), ex.GetType()); + } + + try + { + AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + + } + catch (Exception ex) + { + Assert.Equal(typeof(MalApiRequestException), ex.GetType()); + Assert.Equal("Failed to log in. Recheck credentials.", ex.Message); + } + } + } } } diff --git a/MalApi.IntegrationTests/UpdateUserMangaTest.cs b/MalApi.IntegrationTests/UpdateUserMangaTest.cs index 2f2f226..6af21fb 100644 --- a/MalApi.IntegrationTests/UpdateUserMangaTest.cs +++ b/MalApi.IntegrationTests/UpdateUserMangaTest.cs @@ -13,52 +13,836 @@ namespace MalApi.IntegrationTests public class UpdateUserMangaTest { [Fact] - public void AInitialize() + public void UpdateMangaForUserTest() { - System.Environment.SetEnvironmentVariable("IntegrationTestMalUsername", "user"); - System.Environment.SetEnvironmentVariable("IntegrationTestMalPassword", "password"); + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; - System.Environment.SetEnvironmentVariable("IntegrationTestMangaId", "952"); + MangaUpdate baseInfo = new MangaUpdate() + { + Chapter = 1, + Volume = 2, + Status = MangaCompletionStatus.Reading, + Score = 3, + TimesReread = 1, + RereadValue = 2, // low + DateStart = new DateTime(2017, 10, 1), + DateFinish = new DateTime(2017, 10, 5), + Priority = 0, // low + EnableDiscussion = 0, + EnableRereading = 0, + Comments = "base comment,base comment 2", + // ScanGroup = "scan_group", + Tags = "test base tag, test base tag 2" + }; - System.Environment.SetEnvironmentVariable("IntegrationTestChapterNumber", "10"); - System.Environment.SetEnvironmentVariable("IntegrationTestScore", "8"); - System.Environment.SetEnvironmentVariable("IntegrationTestStatus", "1"); + MangaUpdate updateInfo = new MangaUpdate() + { + Chapter = 162, + Volume = 18, + Status = MangaCompletionStatus.Completed, + Score = 10, + TimesReread = 2, + RereadValue = 4, // high + DateStart = new DateTime(2017, 12, 10), + DateFinish = new DateTime(2017, 12, 15), + Priority = 1, // medium + EnableDiscussion = 1, + EnableRereading = 1, + Comments = "test updated comment, test updated comment2", + // ScanGroup = "scan_group_updated", + Tags = "test updated tag, test updated tag 2" + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, baseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(baseInfo.Chapter, baseReults.Chapter); + Assert.Equal(baseInfo.Volume, baseReults.Volume); + Assert.Equal(baseInfo.Status, baseReults.Status); + Assert.Equal(baseInfo.Score, baseReults.Score); + Assert.Equal(baseInfo.TimesReread, baseReults.TimesReread); + Assert.Equal(baseInfo.RereadValue, baseReults.RereadValue); + Assert.Equal(baseInfo.DateStart, baseReults.DateStart); + Assert.Equal(baseInfo.DateFinish, baseReults.DateFinish); + Assert.Equal(baseInfo.Priority, baseReults.Priority); + Assert.Equal(baseInfo.EnableDiscussion, baseReults.EnableDiscussion); + Assert.Equal(baseInfo.EnableRereading, baseReults.EnableRereading); + Assert.Equal(baseInfo.Comments, baseReults.Comments); + Assert.Equal(baseInfo.Tags, baseReults.Tags); + + result = api.UpdateMangaForUser(mangaId, updateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(updateInfo.Chapter, updatedResults.Chapter); + Assert.Equal(updateInfo.Volume, updatedResults.Volume); + Assert.Equal(updateInfo.Status, updatedResults.Status); + Assert.Equal(updateInfo.Score, updatedResults.Score); + Assert.Equal(updateInfo.TimesReread, updatedResults.TimesReread); + Assert.Equal(updateInfo.RereadValue, updatedResults.RereadValue); + Assert.Equal(updateInfo.DateStart, updatedResults.DateStart); + Assert.Equal(updateInfo.DateFinish, updatedResults.DateFinish); + Assert.Equal(updateInfo.Priority, updatedResults.Priority); + Assert.Equal(updateInfo.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(updateInfo.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(updateInfo.Comments, updatedResults.Comments); + Assert.Equal(updateInfo.Tags, updatedResults.Tags); + + // Assert all values have been changed + Assert.NotEqual(baseReults.Chapter, updatedResults.Chapter); + Assert.NotEqual(baseReults.Volume, updatedResults.Volume); + Assert.NotEqual(baseReults.Status, updatedResults.Status); + Assert.NotEqual(baseReults.Score, updatedResults.Score); + Assert.NotEqual(baseReults.TimesReread, updatedResults.TimesReread); + Assert.NotEqual(baseReults.RereadValue, updatedResults.RereadValue); + Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); + Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); + Assert.NotEqual(baseReults.Priority, updatedResults.Priority); + Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.NotEqual(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.NotEqual(baseReults.Comments, updatedResults.Comments); + Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + } } [Fact] - public void UpdateMangaForUserTest() + public void UpdateMangaChapterForUserTest() { - string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); - string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); - int mangaId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestMangaId")); - MangaUpdate updateInfo = new MangaUpdate() + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + Chapter = 1 + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + Chapter = 162 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Chapter, baseReults.Chapter); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Chapter, updatedResults.Chapter); + + // Assert that only the chapter has been changed + Assert.NotEqual(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaVolumeForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + Volume = 2 + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + Volume = 18 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Volume, baseReults.Volume); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Volume, updatedResults.Volume); + + // Assert that only the volume has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.NotEqual(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaStatusForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + Status = MangaCompletionStatus.Reading + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + Status = MangaCompletionStatus.Completed + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Status, baseReults.Status); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Status, updatedResults.Status); + + // Assert that only the status has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.NotEqual(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaScoreForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + Score = 3 + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + Score = 10 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Score, baseReults.Score); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Score, updatedResults.Score); + + // Assert that only the score has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.NotEqual(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaTimesRereadForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + TimesReread = 1 + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + TimesReread = 2 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.TimesReread, baseReults.TimesReread); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.TimesReread, updatedResults.TimesReread); + + // Assert that only the times reread has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.NotEqual(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaRereadValueForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + RereadValue = 2 // high + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + RereadValue = 4, // high + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.RereadValue, baseReults.RereadValue); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.RereadValue, updatedResults.RereadValue); + + // Assert that only the rearead value has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.NotEqual(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaDateStartForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + DateStart = new DateTime(2017, 10, 1) + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() { - Chapter = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestChapterNumber")), - Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), - Status = (MangaCompletionStatus)int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestStatus")) + DateStart = new DateTime(2017, 12, 10) }; using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, updateInfo, username, password); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.DateStart, baseReults.DateStart); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.DateStart, updatedResults.DateStart); + + // Assert that only the date start has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaDateFinishForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + DateFinish = new DateTime(2017, 10, 5) + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + DateFinish = new DateTime(2017, 12, 15) + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.DateFinish, baseReults.DateFinish); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.DateFinish, updatedResults.DateFinish); + + // Assert that only the date finish has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaPriorityForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + Priority = 0, // low + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + Priority = 1, // medium + }; + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Priority, baseReults.Priority); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Priority, updatedResults.Priority); + + // Assert that only the priority has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.NotEqual(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); } } [Fact] - public void GetMangaListForUserCanceled() + public void UpdateMangaEnableDiscussionForUserTest() { - string username = System.Environment.GetEnvironmentVariable("IntegrationTestMalUsername"); - string password = System.Environment.GetEnvironmentVariable("IntegrationTestMalPassword"); + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + EnableDiscussion = 0 + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + EnableDiscussion = 1 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.EnableDiscussion, baseReults.EnableDiscussion); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.EnableDiscussion, updatedResults.EnableDiscussion); + + // Assert that only the enable discussion has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaEnableRereadingForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + EnableRereading = 0 + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + EnableRereading = 1 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.EnableRereading, baseReults.EnableRereading); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.EnableRereading, updatedResults.EnableRereading); + + // Assert that only the enable rereading has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.NotEqual(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaCommentsorUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + Comments = "base comment,base comment 2" + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + Comments = "test updated comment, test updated comment2" + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Comments, baseReults.Comments); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Comments, updatedResults.Comments); + + // Assert that only the comments has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.NotEqual(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaTagsForUserTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + Tags = "test base tag, test base tag 2" + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + Tags = "test updated tag, test updated tag 2" + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Tags, baseReults.Tags); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Tags, updatedResults.Tags); + + // Assert that only the tags has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + } + } + + [Fact] + public void UpdateMangaForUserCanceled() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; - int mangaId = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestMangaId")); MangaUpdate updateInfo = new MangaUpdate() { - Chapter = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestChapterNumber")), - Score = int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestScore")), - Status = (MangaCompletionStatus)int.Parse(System.Environment.GetEnvironmentVariable("IntegrationTestStatus")) + Chapter = 162, + Volume = 18, + Status = MangaCompletionStatus.Completed, + Score = 10, + TimesReread = 2, + RereadValue = 4, // high + DateStart = new DateTime(2017, 12, 10), + DateFinish = new DateTime(2017, 12, 15), + Priority = 1, // medium + EnableDiscussion = 1, + EnableRereading = 1, + Comments = "test updated comment, test updated comment2", + // ScanGroup = "scan_group_updated", + Tags = "test updated tag, test updated tag 2" }; using (MyAnimeListApi api = new MyAnimeListApi()) @@ -69,5 +853,50 @@ public void GetMangaListForUserCanceled() Assert.Throws(() => userLookupTask.GetAwaiter().GetResult()); } } + + [Fact] + public void IncorrectUsernameMangaChapterUpdateTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + username += "test"; + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + // Monster + int mangaId = 1; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + Chapter = 1 + }; + + MangaUpdate partialUpdateInfo = new MangaUpdate() + { + Chapter = 162 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + try + { + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + + } + catch (Exception ex) + { + Assert.Equal(typeof(MalApiRequestException), ex.GetType()); + } + + try + { + MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + + } + catch (Exception ex) + { + Assert.Equal(typeof(MalApiRequestException), ex.GetType()); + Assert.Equal("Failed to log in. Recheck credentials.", ex.Message); + } + } + } } } diff --git a/MalApi.IntegrationTests/readme.txt b/MalApi.IntegrationTests/readme.txt index ea33859..94b8228 100644 --- a/MalApi.IntegrationTests/readme.txt +++ b/MalApi.IntegrationTests/readme.txt @@ -1 +1,12 @@ -No special setup is needed in order to run these tests. MAL seems to no longer require an API key. \ No newline at end of file +MAL seems to no longer require an API key. + +In order for some tests to pass environmental variables need to be set. +These variable are the username and passowrd of a MAL account. +The requirements towards the account is that it has the 'Cowboy Bebop' anime and the 'Monster' manga added to it. + +Steps to set up environmental variables: +1) Follow these instructions to get to the needed window: https://serverfault.com/q/351129 or try searching for 'environment' in the start menu, if you'd like to save those precious seconds. + +2) Add two new user variables called 'MAL_USERNAME' and 'MAL_PASSWORD' with the appropriate values for the account you wish to be used with these tests. + +3) Done! Go run the tests and see if everything's OK. diff --git a/MalApi.UnitTests/Cowboy_Bebop.htm b/MalApi.UnitTests/Cowboy_Bebop.htm new file mode 100644 index 0000000..27ded71 --- /dev/null +++ b/MalApi.UnitTests/Cowboy_Bebop.htm @@ -0,0 +1 @@ + MyAnimeList.net

Edit Anime

Edit Anime
Anime Title Cowboy Bebop
Status
Episodes Watched + / 26 History
Your Score
Start Date Month: Day: Year: Insert Today
Finish Date Month: Day: Year: Insert Today
Hide Advanced
Show Advanced
Tags
Priority
Storage
Total Times
Re-watched Series
Rewatch Value
Comments
Ask to Discuss?
Post to SNS
\ No newline at end of file diff --git a/MalApi.UnitTests/MalApi.UnitTests.csproj b/MalApi.UnitTests/MalApi.UnitTests.csproj index 7c83170..51caa38 100644 --- a/MalApi.UnitTests/MalApi.UnitTests.csproj +++ b/MalApi.UnitTests/MalApi.UnitTests.csproj @@ -10,9 +10,13 @@ true - - + + + + + + @@ -31,10 +35,16 @@ + + Never + - - + + + + + diff --git a/MalApi.UnitTests/MalAppInfoXmlTests.cs b/MalApi.UnitTests/MalAppInfoXmlTests.cs index a6549a1..bd7da81 100644 --- a/MalApi.UnitTests/MalAppInfoXmlTests.cs +++ b/MalApi.UnitTests/MalAppInfoXmlTests.cs @@ -14,19 +14,37 @@ public partial class MalAppInfoXmlTests [Fact] public void ParseWithTextReaderTest() { - using (TextReader reader = Helpers.GetResourceStream("test.xml")) + using (TextReader reader = Helpers.GetResourceStream("test_anime.xml")) { MalUserLookupResults results = MalAppInfoXml.Parse(reader); - DoAsserts(results); + DoAnimeAsserts(results); } } [Fact] - public void ParseWithXElementTest() + public void ParseWithTextReaderMangaTest() { - XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_clean.xml")); + using (TextReader reader = Helpers.GetResourceStream("test_manga.xml")) + { + MalUserLookupResults results = MalAppInfoXml.Parse(reader); + DoMangaAsserts(results); + } + } + + [Fact] + public void ParseWithXElementAnimeTest() + { + XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_anime_clean.xml")); + MalUserLookupResults results = MalAppInfoXml.ParseResults(doc); + DoAnimeAsserts(results); + } + + [Fact] + public void ParseWithXElementMangaTest() + { + XDocument doc = XDocument.Parse(Helpers.GetResourceText("test_manga_clean.xml")); MalUserLookupResults results = MalAppInfoXml.ParseResults(doc); - DoAsserts(results); + DoMangaAsserts(results); } [Fact] @@ -61,7 +79,7 @@ public void ParseOldInvalidUserWithXElementTest() Assert.Throws(() => MalAppInfoXml.ParseResults(doc)); } - private void DoAsserts(MalUserLookupResults results) + private void DoAnimeAsserts(MalUserLookupResults results) { Assert.Equal("LordHighCaptain", results.CanonicalUserName); Assert.Equal(158667, results.UserId); @@ -106,6 +124,51 @@ private void DoAsserts(MalUserLookupResults results) Assert.Equal(new List() { "test&test", "< less than", "> greater than", "apos '", "quote \"", "hex ö", "dec !", "control character" }, entry.Tags); } + + private void DoMangaAsserts(MalUserLookupResults results) + { + Assert.Equal("naps250", results.CanonicalUserName); + Assert.Equal(5544903, results.UserId); + Assert.Equal(6, results.MangaList.Count); + + MyMangaListEntry entry = results.MangaList.Where(manga => manga.MangaInfo.MangaId == 2).First(); + Assert.Equal("Berserk", entry.MangaInfo.Title); + Assert.Equal(MalMangaType.Manga, entry.MangaInfo.Type); + entry.MangaInfo.Synonyms.Should().BeEquivalentTo(new List() { "Berserk: The Prototype" }); + + Assert.Equal(352, entry.NumChaptersRead); + Assert.Equal(10, entry.Score); + Assert.Equal(MangaCompletionStatus.Reading, entry.Status); + + // Test tags with Equal, not equivalent, because order in tags matters + Assert.Equal(new List() { "CLANG", "Miura pls" }, entry.Tags); + + entry = results.MangaList.Where(manga => manga.MangaInfo.MangaId == 9115).First(); + Assert.Equal("Ookami to Koushinryou", entry.MangaInfo.Title); + Assert.Equal(MalMangaType.Novel, entry.MangaInfo.Type); + entry.MangaInfo.Synonyms.Should().BeEquivalentTo(new List() { "Okami to Koshinryo", "Spice and Wolf", "Spice & Wolf" }); + Assert.Equal((decimal?)null, entry.Score); + Assert.Equal(0, entry.NumChaptersRead); + Assert.Equal(MangaCompletionStatus.Completed, entry.Status); + Assert.Equal(new List(), entry.Tags); + + entry = results.MangaList.Where(manga => manga.MangaInfo.MangaId == 1).First(); + Assert.Equal("Monster", entry.MangaInfo.Title); + + // Make sure synonyms that are the same as the real name get filtered out + entry.MangaInfo.Synonyms.Should().BeEquivalentTo(new List()); + + entry = results.MangaList.Where(manga => manga.MangaInfo.Title == "Test").First(); + // Make sure that is the same as + entry.MangaInfo.Synonyms.Should().BeEquivalentTo(new List()); + Assert.Equal(new UncertainDate(2010, 2, 6), entry.MangaInfo.StartDate); + Assert.Equal(UncertainDate.Unknown, entry.MangaInfo.EndDate); + Assert.Equal("https://myanimelist.cdn-dena.com/images/manga/2/159423.jpg", entry.MangaInfo.ImageUrl); + Assert.Equal(new UncertainDate(year: null, month: 2, day: null), entry.MyStartDate); + Assert.Equal(UncertainDate.Unknown, entry.MyFinishDate); + Assert.Equal(new DateTime(year: 2011, month: 4, day: 2, hour: 22, minute: 50, second: 58, kind: DateTimeKind.Utc), entry.MyLastUpdate); + Assert.Equal(new List() { "test&test", "< less than", "> greater than", "apos '", "quote \"", "hex ö", "dec !", "control character" }, entry.Tags); + } } } diff --git a/MalApi.UnitTests/Monster.htm b/MalApi.UnitTests/Monster.htm new file mode 100644 index 0000000..380e5d4 --- /dev/null +++ b/MalApi.UnitTests/Monster.htm @@ -0,0 +1 @@ + MyAnimeList.net

Edit Manga

Edit Manga
Manga Title Monster
Status
Volumes Read + / 18
Chapters Read + / 162 History
Your Score
Start Date Month: Day: Year: Insert Today
Finish Date Month: Day: Year: Insert Today
Hide Advanced
Show Advanced
Tags
Priority
Storage
Total Times
Re-read
Re-read Value
Comments
Ask to Discuss?
Post to SNS
\ No newline at end of file diff --git a/MalApi.UnitTests/MyAnimeListApiTests.cs b/MalApi.UnitTests/MyAnimeListApiTests.cs index efb50ba..12ae0f0 100644 --- a/MalApi.UnitTests/MyAnimeListApiTests.cs +++ b/MalApi.UnitTests/MyAnimeListApiTests.cs @@ -34,6 +34,101 @@ public void TestScrapeAnimeDetailsFromHtml() results.Genres.Should().BeEquivalentTo(expectedGenres); } } + + [Fact] + public void TestScrapeUserAnimeDetailsFromHtml() + { + string html; + using (StreamReader reader = Helpers.GetResourceStream("Cowboy_Bebop.htm")) + { + html = reader.ReadToEnd(); + } + + AnimeUpdate info = new AnimeUpdate() + { + Episode = 26, + Status = AnimeCompletionStatus.Completed, + Score = 8, + StorageType = 5, // VHS + StorageValue = 123, + TimesRewatched = 2, + RewatchValue = 4, // high + DateStart = new DateTime(2017, 12, 10), + DateFinish = new DateTime(2017, 12, 15), + Priority = 1, // medium + EnableDiscussion = 1, + EnableRewatching = 1, + Comments = "test updated comment, test updated comment2", + Tags = "test updated tag, test updated tag 2" + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + AnimeUpdate results = api.ScrapeUserAnimeDetailsFromHtml(html); + + Assert.Equal(info.Episode, results.Episode); + Assert.Equal(info.Status, results.Status); + Assert.Equal(info.Score, results.Score); + Assert.Equal(info.StorageType, results.StorageType); + Assert.Equal(info.StorageValue, results.StorageValue); + Assert.Equal(info.TimesRewatched, results.TimesRewatched); + Assert.Equal(info.RewatchValue, results.RewatchValue); + Assert.Equal(info.DateStart, results.DateStart); + Assert.Equal(info.DateFinish, results.DateFinish); + Assert.Equal(info.Priority, results.Priority); + Assert.Equal(info.EnableDiscussion, results.EnableDiscussion); + Assert.Equal(info.EnableRewatching, results.EnableRewatching); + Assert.Equal(info.Comments, results.Comments); + Assert.Equal(info.Tags, results.Tags); + } + } + + [Fact] + public void TestScrapeUserMangaDetailsFromHtml() + { + string html; + using (StreamReader reader = Helpers.GetResourceStream("Monster.htm")) + { + html = reader.ReadToEnd(); + } + + MangaUpdate info = new MangaUpdate() + { + Chapter = 162, + Volume = 18, + Status = MangaCompletionStatus.Completed, + Score = 10, + TimesReread = 2, + RereadValue = 4, // high + DateStart = new DateTime(2017, 12, 10), + DateFinish = new DateTime(2017, 12, 15), + Priority = 1, // medium + EnableDiscussion = 1, + EnableRereading = 1, + Comments = "test updated comment, test updated comment2", + // ScanGroup = "scan_group_updated", + Tags = "test updated tag, test updated tag 2" + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + MangaUpdate results = api.ScrapeUserMangaDetailsFromHtml(html); + + Assert.Equal(info.Chapter, results.Chapter); + Assert.Equal(info.Volume, results.Volume); + Assert.Equal(info.Status, results.Status); + Assert.Equal(info.Score, results.Score); + Assert.Equal(info.TimesReread, results.TimesReread); + Assert.Equal(info.RereadValue, results.RereadValue); + Assert.Equal(info.DateStart, results.DateStart); + Assert.Equal(info.DateFinish, results.DateFinish); + Assert.Equal(info.Priority, results.Priority); + Assert.Equal(info.EnableDiscussion, results.EnableDiscussion); + Assert.Equal(info.EnableRereading, results.EnableRereading); + Assert.Equal(info.Comments, results.Comments); + Assert.Equal(info.Tags, results.Tags); + } + } } } diff --git a/MalApi.UnitTests/test.xml b/MalApi.UnitTests/test_anime.xml similarity index 100% rename from MalApi.UnitTests/test.xml rename to MalApi.UnitTests/test_anime.xml diff --git a/MalApi.UnitTests/test_clean.xml b/MalApi.UnitTests/test_anime_clean.xml similarity index 100% rename from MalApi.UnitTests/test_clean.xml rename to MalApi.UnitTests/test_anime_clean.xml diff --git a/MalApi.UnitTests/test_manga.xml b/MalApi.UnitTests/test_manga.xml new file mode 100644 index 0000000..ed0e905 --- /dev/null +++ b/MalApi.UnitTests/test_manga.xml @@ -0,0 +1,151 @@ + + + + 5544903 + naps250 + 22 + 48 + 2 + 3 + 62 + 38.62 + + + 2 + Berserk + Berserk: The Prototype; Berserk + 1 + 0 + 0 + 1 + 1989-08-25 + 0000-00-00 + https://myanimelist.cdn-dena.com/images/manga/1/157931.jpg + 51710571 + 352 + 38 + 0000-00-00 + 0000-00-00 + 10 + 1 + 0 + 0 + 1515800570 + CLANG,, Miura pls + + + 9115 + Ookami to Koushinryou + Okami to Koshinryo; Spice and Wolf; Spice & Wolf + 2 + 0 + 0 + 1 + 2006-02-10 + 0000-00-00 + https://myanimelist.cdn-dena.com/images/manga/2/153860.jpg + 58175226 + 0 + 17 + 0000-00-00 + 0000-00-00 + 0 + 2 + 0 + 0 + 1492361419 + + + + 1 + Monster + ; Monster + 1 + 162 + 18 + 2 + 1994-12-05 + 2001-12-20 + https://myanimelist.cdn-dena.com/images/manga/3/54525.jpg + 51710604 + 1 + 18 + 2017-12-10 + 2017-12-15 + 10 + 2 + 1 + 0 + 1516443916 + test&test, < less than, > greater than, apos ', quote ", hex ö, dec !, control character + + + 988 + Shijou Saikyou no Deshi Kenichi + History's Strongest Disciple Kenichi; Kenichi: The Mightiest Disciple + 1 + 584 + 61 + 2 + 2002-08-09 + 2014-09-17 + https://myanimelist.cdn-dena.com/images/manga/2/169883.jpg + 51710624 + 584 + 61 + 0000-00-00 + 2017-01-28 + 8 + 2 + 0 + 0 + 1485582298 + + + + 12 + Bleach + ; Bleach + 1 + 705 + 74 + 2 + 2001-08-07 + 2016-08-22 + https://myanimelist.cdn-dena.com/images/manga/2/180089.jpg + 51710858 + 705 + 74 + 0000-00-00 + 2017-01-28 + 7 + 2 + 0 + 0 + 1485582249 + + + + 999999 + Test + + 1 + 36 + 3 + 2 + 2010-02-06 + 0000-00-00 + https://myanimelist.cdn-dena.com/images/manga/2/159423.jpg + 58002197 + 36 + 3 + 0000-02-00 + 0000-00-00 + 5 + 2 + 0 + 0 + 1301784658 + test&test, < less than, > greater than, apos ', quote ", hex ö, dec !, control character + + \ No newline at end of file diff --git a/MalApi.UnitTests/test_manga_clean.xml b/MalApi.UnitTests/test_manga_clean.xml new file mode 100644 index 0000000..4d725d0 --- /dev/null +++ b/MalApi.UnitTests/test_manga_clean.xml @@ -0,0 +1,151 @@ + + + + 5544903 + naps250 + 22 + 48 + 2 + 3 + 62 + 38.62 + + + 2 + Berserk + Berserk: The Prototype; Berserk + 1 + 0 + 0 + 1 + 1989-08-25 + 0000-00-00 + https://myanimelist.cdn-dena.com/images/manga/1/157931.jpg + 51710571 + 352 + 38 + 0000-00-00 + 0000-00-00 + 10 + 1 + 0 + 0 + 1515800570 + CLANG, Miura pls + + + 9115 + Ookami to Koushinryou + Okami to Koshinryo; Spice and Wolf; Spice & Wolf + 2 + 0 + 0 + 1 + 2006-02-10 + 0000-00-00 + https://myanimelist.cdn-dena.com/images/manga/2/153860.jpg + 58175226 + 0 + 17 + 0000-00-00 + 0000-00-00 + 0 + 2 + 0 + 0 + 1492361419 + + + + 1 + Monster + ; Monster + 1 + 162 + 18 + 2 + 1994-12-05 + 2001-12-20 + https://myanimelist.cdn-dena.com/images/manga/3/54525.jpg + 51710604 + 1 + 18 + 2017-12-10 + 2017-12-15 + 10 + 2 + 1 + 0 + 1516443916 + test updated tag, test updated tag 2 + + + 988 + Shijou Saikyou no Deshi Kenichi + History's Strongest Disciple Kenichi; Kenichi: The Mightiest Disciple + 1 + 584 + 61 + 2 + 2002-08-09 + 2014-09-17 + https://myanimelist.cdn-dena.com/images/manga/2/169883.jpg + 51710624 + 584 + 61 + 0000-00-00 + 2017-01-28 + 8 + 2 + 0 + 0 + 1485582298 + + + + 12 + Bleach + ; Bleach + 1 + 705 + 74 + 2 + 2001-08-07 + 2016-08-22 + https://myanimelist.cdn-dena.com/images/manga/2/180089.jpg + 51710858 + 705 + 74 + 0000-00-00 + 2017-01-28 + 7 + 2 + 0 + 0 + 1485582249 + + + + 999999 + Test + + 1 + 36 + 3 + 2 + 2010-02-06 + 0000-00-00 + https://myanimelist.cdn-dena.com/images/manga/2/159423.jpg + 58002197 + 36 + 3 + 0000-02-00 + 0000-00-00 + 5 + 2 + 0 + 0 + 1301784658 + test&test, < less than, > greater than, apos ', quote ", hex ö, dec !, control character + + \ No newline at end of file diff --git a/MalApi/Anime/AnimeUpdate.cs b/MalApi/Anime/AnimeUpdate.cs index 670f5f9..121b22d 100644 --- a/MalApi/Anime/AnimeUpdate.cs +++ b/MalApi/Anime/AnimeUpdate.cs @@ -90,20 +90,20 @@ public string GenerateXml() XDocument document = new XDocument( new XDeclaration("1.0", "UTF-8", null), new XElement("entry", - new XElement("episode", Episode), - new XElement("status", (int?)Status), - new XElement("score", Score), - new XElement("storage_type", StorageType), - new XElement("storage_value", StorageValue), - new XElement("times_rewatched", TimesRewatched), - new XElement("rewatch_value", RewatchValue), - new XElement("date_start", FormattedDateStart), - new XElement("date_finish", FormattedDateFinish), - new XElement("priority", Priority), - new XElement("enable_discussion", EnableDiscussion), - new XElement("enable_rewatching", EnableRewatching), - new XElement("comments", Comments), - new XElement("tags", Tags) + Episode != null ? new XElement("episode", Episode) : null, + Status != null ? new XElement("status", (int?)Status) : null, + Score != null ? new XElement("score", Score) : null, + StorageType != null ? new XElement("storage_type", StorageType) : null, + StorageValue != null ? new XElement("storage_value", StorageValue) : null, + TimesRewatched != null ? new XElement("times_rewatched", TimesRewatched) : null, + RewatchValue != null ? new XElement("rewatch_value", RewatchValue) : null, + FormattedDateStart != null ? new XElement("date_start", FormattedDateStart) : null, + FormattedDateFinish != null ? new XElement("date_finish", FormattedDateFinish) : null, + Priority != null ? new XElement("priority", Priority) : null, + EnableDiscussion != null ? new XElement("enable_discussion", EnableDiscussion) : null, + EnableRewatching != null ? new XElement("enable_rewatching", EnableRewatching) : null, + Comments != null ? new XElement("comments", Comments) : null, + Tags != null ? new XElement("tags", Tags) : null ) ); diff --git a/MalApi/MalApi.csproj b/MalApi/MalApi.csproj index 072534c..f5db073 100644 --- a/MalApi/MalApi.csproj +++ b/MalApi/MalApi.csproj @@ -41,6 +41,7 @@ + diff --git a/MalApi/Manga/MangaUpdate.cs b/MalApi/Manga/MangaUpdate.cs index bdc684e..173bef6 100644 --- a/MalApi/Manga/MangaUpdate.cs +++ b/MalApi/Manga/MangaUpdate.cs @@ -93,21 +93,21 @@ public string GenerateXml() XDocument document = new XDocument( new XDeclaration("1.0", "UTF-8", null), new XElement("entry", - new XElement("chapter", Chapter), - new XElement("volume", Volume), - new XElement("status", (int?)Status), - new XElement("score", Score), - new XElement("times_reread", TimesReread), - new XElement("reread_value", RereadValue), - new XElement("date_start", FormattedDateStart), - new XElement("date_finish", FormattedDateFinish), - new XElement("priority", Priority), - new XElement("enable_discussion", EnableDiscussion), - new XElement("enable_rereading", EnableRereading), - new XElement("comments", Comments), - new XElement("scan_group", ScanGroup), - new XElement("tags", Tags), - new XElement("retail_volumes", RetailVolumes) + Chapter != null ? new XElement("chapter", Chapter) : null, + Volume != null ? new XElement("volume", Volume) : null, + Status != null ? new XElement("status", (int?)Status) : null, + Score != null ? new XElement("score", Score) : null, + TimesReread != null ? new XElement("times_reread", TimesReread) : null, + RereadValue != null ? new XElement("reread_value", RereadValue) : null, + FormattedDateStart != null ? new XElement("date_start", FormattedDateStart) : null, + FormattedDateFinish != null ? new XElement("date_finish", FormattedDateFinish) : null, + Priority != null ? new XElement("priority", Priority) : null, + EnableDiscussion != null ? new XElement("enable_discussion", EnableDiscussion) : null, + EnableRereading != null ? new XElement("enable_rereading", EnableRereading) : null, + Comments != null ? new XElement("comments", Comments) : null, + // ScanGroup != null ? new XElement("scan_group", ScanGroup) : null, + Tags != null ? new XElement("tags", Tags) : null, + RetailVolumes != null ? new XElement("retail_volumes", RetailVolumes) : null ) ); diff --git a/MalApi/MyAnimeListApi.cs b/MalApi/MyAnimeListApi.cs index f2f7cd4..6833a4e 100644 --- a/MalApi/MyAnimeListApi.cs +++ b/MalApi/MyAnimeListApi.cs @@ -8,6 +8,7 @@ using System.Net.Http.Headers; using System.Threading.Tasks; using System.Threading; +using HtmlAgilityPack; namespace MalApi { @@ -16,6 +17,11 @@ namespace MalApi ///
public class MyAnimeListApi : IMyAnimeListApi { + private static readonly string NoRedirectMalUri = "https://myanimelist.net/pressroom"; + private static readonly string LoginUri = "https://myanimelist.net/login.php"; + private static readonly string UserAnimeDetailsUri = "https://myanimelist.net/editlist.php?type=anime&id={0}"; + private static readonly string UserMangaDetailsUri = "https://myanimelist.net/panel.php?go=editmanga&id={0}"; + private static readonly string AnimeDetailsUrlFormat = "https://myanimelist.net/anime/{0}"; private const string RecentOnlineUsersUri = "https://myanimelist.net/users.php"; @@ -47,12 +53,14 @@ public int TimeoutInMs private HttpClientHandler m_httpHandler; private HttpClient m_httpClient; + private string CsrfToken { get; set; } + public MyAnimeListApi() { m_httpHandler = new HttpClientHandler() { AllowAutoRedirect = true, - UseCookies = false, + UseCookies = true, // Very important optimization! Time to get an anime list of ~150 entries 2.6s -> 0.7s AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, @@ -328,15 +336,15 @@ public async Task UpdateAnimeForUserAsync(int animeId, AnimeUpdate updat request.Content = new FormUrlEncodedContent(new KeyValuePair[] { new KeyValuePair("data", xml) }); string result = await ProcessRequestAsync(request, responseProcessingFunc, cancellationToken: cancellationToken, - baseErrorMessage: string.Format("Failed updating anime entry for anime ID {0}, user {0} using url {1}", animeId, user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); + baseErrorMessage: string.Format("Failed updating anime entry for anime ID {0}, user {1} using url {2}", animeId, user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); - Logging.Log.InfoFormat("Successfully updated anime entry for anime ID {0} and user {0}", animeId, user); + Logging.Log.InfoFormat("Successfully updated anime entry for anime ID {0} and user {1}", animeId, user); return result; } catch (OperationCanceledException) { - Logging.Log.InfoFormat("Canceled updating anime entry for MAL anime ID {0} and user {0}", animeId, user); + Logging.Log.InfoFormat("Canceled updating anime entry for MAL anime ID {0} and user {1}", animeId, user); throw; } } @@ -422,15 +430,15 @@ public async Task UpdateMangaForUserAsync(int mangaId, MangaUpdate updat request.Content = new FormUrlEncodedContent(new KeyValuePair[] { new KeyValuePair("data", xml) }); string result = await ProcessRequestAsync(request, responseProcessingFunc, cancellationToken: cancellationToken, - baseErrorMessage: string.Format("Failed updating manga entry for manga ID {0}, user {0} using url {1}", mangaId, user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); + baseErrorMessage: string.Format("Failed updating manga entry for manga ID {0}, user {1} using url {2}", mangaId, user, userInfoUri)).ConfigureAwait(continueOnCapturedContext: false); - Logging.Log.InfoFormat("Successfully updated manga entry for manga ID {0} and user {0}", mangaId, user); + Logging.Log.InfoFormat("Successfully updated manga entry for manga ID {0} and user {1}", mangaId, user); return result; } catch (OperationCanceledException) { - Logging.Log.InfoFormat("Canceled updating manga entry for MAL manga ID {0} and user {0}", mangaId, user); + Logging.Log.InfoFormat("Canceled updating manga entry for MAL manga ID {0} and user {1}", mangaId, user); throw; } } @@ -573,6 +581,16 @@ public Task GetAnimeDetailsAsync(int animeId) return GetAnimeDetailsAsync(animeId, CancellationToken.None); } + public Task GetUserAnimeDetailsAsync(string username, string password, int animeId) + { + return GetUserAnimeDetailsAsync(username, password, animeId, CancellationToken.None); + } + + public Task GetUserMangaDetailsAsync(string username, string password, int mangaId) + { + return GetUserMangaDetailsAsync(username, password, mangaId, CancellationToken.None); + } + /// /// Gets information from an anime's "details" page. This method uses HTML scraping and so may break if MAL changes the HTML. /// This method does not require a MAL API key. @@ -594,6 +612,7 @@ public async Task GetAnimeDetailsAsync(int animeId, Cancell httpErrorStatusHandler: GetAnimeDetailsHttpErrorStatusHandler, cancellationToken: cancellationToken, baseErrorMessage: string.Format("Failed getting anime details for anime ID {0}.", animeId)) .ConfigureAwait(continueOnCapturedContext: false); + Logging.Log.InfoFormat("Successfully got details from {0}.", url); return results; } @@ -604,6 +623,116 @@ public async Task GetAnimeDetailsAsync(int animeId, Cancell } } + public async Task GetUserAnimeDetailsAsync(string username, string password, int animeId, CancellationToken cancellationToken) + { + string url = NoRedirectMalUri; + + HttpRequestMessage request = InitNewRequest(url, HttpMethod.Get); + + Logging.Log.InfoFormat("Getting user anime details for anime ID {0} from {1}.", animeId, url); + + try + { + // Get CSRF token + await ProcessRequestAsync(request, ParseCsrfTokenFromHtml, + cancellationToken: cancellationToken, + baseErrorMessage: "Failed connecting to MAL") + .ConfigureAwait(continueOnCapturedContext: false); + + // Login through the web form + url = LoginUri; + request = InitNewRequest(url, HttpMethod.Post); + + var contentPairs = new List> + { + new KeyValuePair("user_name", username), + new KeyValuePair("password", password), + new KeyValuePair("cookie", "1"), + new KeyValuePair("sublogin", "Login"), + new KeyValuePair("submit", "1"), + new KeyValuePair("csrf_token", CsrfToken) + }; + var content = new FormUrlEncodedContent(contentPairs); + request.Content = content; + + await ProcessRequestAsync(request, WebFormLoginHandler, + cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed to log in for user {0}.", username)) + .ConfigureAwait(continueOnCapturedContext: false); + + // Retrieve anime specific info for user + url = string.Format(UserAnimeDetailsUri, animeId); + request = InitNewRequest(url, HttpMethod.Get); + + AnimeUpdate results = await ProcessRequestAsync(request, ScrapeUserAnimeDetailsFromHtml, + cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed getting user anime details for user {0} anime ID {1}.", username, animeId)) + .ConfigureAwait(continueOnCapturedContext: false); + Logging.Log.InfoFormat("Successfully got details from {0}.", url); + return results; + } + catch (OperationCanceledException) + { + Logging.Log.InfoFormat("Canceled getting anime details for anime ID {0}.", animeId); + throw; + } + } + + public async Task GetUserMangaDetailsAsync(string username, string password, int mangaId, CancellationToken cancellationToken) + { + string url = NoRedirectMalUri; + + HttpRequestMessage request = InitNewRequest(url, HttpMethod.Get); + + Logging.Log.InfoFormat("Getting user manga details for manga ID {0} from {1}.", mangaId, url); + + try + { + // Get CSRF token + await ProcessRequestAsync(request, ParseCsrfTokenFromHtml, + cancellationToken: cancellationToken, + baseErrorMessage: "Failed connecting to MAL") + .ConfigureAwait(continueOnCapturedContext: false); + + // Login through the web form + url = LoginUri; + request = InitNewRequest(url, HttpMethod.Post); + + var contentPairs = new List> + { + new KeyValuePair("user_name", username), + new KeyValuePair("password", password), + new KeyValuePair("cookie", "1"), + new KeyValuePair("sublogin", "Login"), + new KeyValuePair("submit", "1"), + new KeyValuePair("csrf_token", CsrfToken) + }; + var content = new FormUrlEncodedContent(contentPairs); + request.Content = content; + + await ProcessRequestAsync(request, WebFormLoginHandler, + cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed to log in for user {0}.", username)) + .ConfigureAwait(continueOnCapturedContext: false); + + // Retrieve anime specific info for user + url = string.Format(UserMangaDetailsUri, mangaId); + request = InitNewRequest(url, HttpMethod.Get); + + MangaUpdate results = await ProcessRequestAsync(request, ScrapeUserMangaDetailsFromHtml, + cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed getting user manga details for user {0} manga ID {1}.", username, mangaId)) + .ConfigureAwait(continueOnCapturedContext: false); + Logging.Log.InfoFormat("Successfully got details from {0}.", url); + return results; + } + catch (OperationCanceledException) + { + Logging.Log.InfoFormat("Canceled getting anime details for anime ID {0}.", mangaId); + throw; + } + } + /// /// Gets information from an anime's "details" page. This method uses HTML scraping and so may break if MAL changes the HTML. /// This method does not require a MAL API key. @@ -616,6 +745,16 @@ public AnimeDetailsResults GetAnimeDetails(int animeId) return GetAnimeDetailsAsync(animeId).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); } + public AnimeUpdate GetUserAnimeDetails(string username, string password, int animeId) + { + return GetUserAnimeDetailsAsync(username, password, animeId).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); + } + + public MangaUpdate GetUserMangaDetails(string username, string password, int mangaId) + { + return GetUserMangaDetailsAsync(username, password, mangaId).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); + } + // If getting anime details page returned a 404, throw a MalAnimeNotFound exception instead of letting // a generic MalApiException be thrown. private static AnimeDetailsResults GetAnimeDetailsHttpErrorStatusHandler(HttpResponseMessage response, int animeId, out bool handled) @@ -655,6 +794,368 @@ internal AnimeDetailsResults ScrapeAnimeDetailsFromHtml(string animeDetailsHtml, return new AnimeDetailsResults(genres); } + // internal for unit testing + public string ParseCsrfTokenFromHtml(string html) + { + Match match = Regex.Match(html, @""); + if (match.Success) + { + CsrfToken = match.Groups[1].ToString(); + } + + return CsrfToken; + } + + // internal for unit testing + public string WebFormLoginHandler(string responseBody) + { + if (responseBody.Contains("Your username or password is incorrect.")) + { + throw new MalApiRequestException("Failed to log in. Recheck credentials."); + } + + return null; + } + + // internal for unit testing + internal AnimeUpdate ScrapeUserAnimeDetailsFromHtml(string userAnimeDetailsHtml) + { + AnimeUpdate results = new AnimeUpdate(); + + var doc = new HtmlDocument(); + doc.LoadHtml(userAnimeDetailsHtml); + + // Episode + results.Episode = doc.GetElementbyId("add_anime_num_watched_episodes").GetAttributeValue("value", -1); + + // Status + var parentNode = doc.GetElementbyId("add_anime_status"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Status = (AnimeCompletionStatus)childNode.GetAttributeValue("value", -1); + break; + } + } + + // Enable rewatching + results.EnableRewatching = doc.GetElementbyId("add_anime_is_rewatching").Attributes["checked"] == null ? 0 : 1; + + // Score + parentNode = doc.GetElementbyId("add_anime_score"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Score = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Start date + int day = -1; + int month = -1; + int year = -1; + parentNode = doc.GetElementbyId("add_anime_start_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_start_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_start_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateStart = null; + } + else + { + results.DateStart = new DateTime(year, month, day); + } + + // Date finish + parentNode = doc.GetElementbyId("add_anime_finish_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_finish_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_finish_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateFinish = null; + } + else + { + results.DateFinish = new DateTime(year, month, day); + } + + // Tags + results.Tags = doc.GetElementbyId("add_anime_tags").InnerText; + + // Priority + parentNode = doc.GetElementbyId("add_anime_priority"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Priority = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Storage type + parentNode = doc.GetElementbyId("add_anime_storage_type"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.StorageType = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Storage value + results.StorageValue = doc.GetElementbyId("add_anime_storage_value").GetAttributeValue("value", -1); + + // Times rewatched + results.TimesRewatched = doc.GetElementbyId("add_anime_num_watched_times").GetAttributeValue("value", -1); + + // Rewatch value + parentNode = doc.GetElementbyId("add_anime_rewatch_value"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.RewatchValue = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Comments + results.Comments = doc.GetElementbyId("add_anime_comments").InnerText; + + // Enable discussion + parentNode = doc.GetElementbyId("add_anime_is_asked_to_discuss"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + // Because 'Enable discussion = 1' sent for update sets the first options of the dropdown, which corresponds to 0 and vice versa... + int temp = childNode.GetAttributeValue("value", -1); + temp = temp == 1 ? 0 : 1; + results.EnableDiscussion = temp; + break; + } + } + + return results; + } + + // internal for unit testing + internal MangaUpdate ScrapeUserMangaDetailsFromHtml(string userMangaDetailsHtml) + { + MangaUpdate results = new MangaUpdate(); + + var doc = new HtmlDocument(); + doc.LoadHtml(userMangaDetailsHtml); + + // Chapter + results.Chapter = doc.GetElementbyId("add_manga_num_read_chapters").GetAttributeValue("value", -1); + + // Volume + results.Volume = doc.GetElementbyId("add_manga_num_read_volumes").GetAttributeValue("value", -1); + + // Status + var parentNode = doc.GetElementbyId("add_manga_status"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Status = (MangaCompletionStatus)childNode.GetAttributeValue("value", -1); + break; + } + } + + // Enable rereading + results.EnableRereading = doc.GetElementbyId("add_manga_is_rereading").Attributes["checked"] == null ? 0 : 1; + + // Score + parentNode = doc.GetElementbyId("add_manga_score"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Score = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Start date + int day = -1; + int month = -1; + int year = -1; + parentNode = doc.GetElementbyId("add_manga_start_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_start_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_start_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateStart = null; + } + else + { + results.DateStart = new DateTime(year, month, day); + } + + // Date finish + parentNode = doc.GetElementbyId("add_manga_finish_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_finish_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_finish_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateFinish = null; + } + else + { + results.DateFinish = new DateTime(year, month, day); + } + + // Tags + results.Tags = doc.GetElementbyId("add_manga_tags").InnerText; + + // Priority + parentNode = doc.GetElementbyId("add_manga_priority"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Priority = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Times reread + results.TimesReread = doc.GetElementbyId("add_manga_num_read_times").GetAttributeValue("value", -1); + + // Reread value + parentNode = doc.GetElementbyId("add_manga_reread_value"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.RereadValue = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Comments + results.Comments = doc.GetElementbyId("add_manga_comments").InnerText; + + // Enable discussion + parentNode = doc.GetElementbyId("add_manga_is_asked_to_discuss"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + // Because 'Enable discussion = 1' sent for update sets the first options of the dropdown, which corresponds to 0 and vice versa... + int temp = childNode.GetAttributeValue("value", -1); + temp = temp == 1 ? 0 : 1; + results.EnableDiscussion = temp; + break; + } + } + + return results; + } + public void Dispose() { m_httpClient.Dispose(); From 4ac22f365bca8baaa14c9d2f54ea999c7906f722 Mon Sep 17 00:00:00 2001 From: Shavarsh Movsesyan Date: Sun, 4 Mar 2018 00:57:28 +0200 Subject: [PATCH 9/9] Updated XUnit packages because current version was no longer working (https://github.com/Microsoft/vstest/issues/811). Removed HtmlAgilityPack (HAP) from the MalApi project. Added HAP to the integration and unit test projects. Moved update test logic to the integration test project. Doubled the scraping methods in the unit test project to keep the scraping method tests and updated the readme.txt in integration test project to include a warning/notification. Added test for non-existant MAL entry. Updating id that is not on your list does nothing but still returns "Updated" response. --- MalApi.IntegrationTests/GetMalDetails.cs | 149 +++ .../GetMangaListForUserTest.cs | 2 - .../GetUserAnimeDetailsTest.cs | 208 ++++ .../GetUserMangaDetailsTest.cs | 198 ++++ .../MalApi.IntegrationTests.csproj | 5 +- .../UpdateUserAnimeTest.cs | 955 +++++++++-------- .../UpdateUserMangaTest.cs | 979 ++++++++++-------- MalApi.IntegrationTests/readme.txt | 2 + MalApi.UnitTests/MalApi.UnitTests.csproj | 5 +- MalApi.UnitTests/MalDetailScrapingUtils.cs | 349 +++++++ MalApi.UnitTests/MyAnimeListApiTests.cs | 4 +- MalApi/MalApi.csproj | 1 - MalApi/MyAnimeListApi.cs | 501 --------- 13 files changed, 1970 insertions(+), 1388 deletions(-) create mode 100644 MalApi.IntegrationTests/GetMalDetails.cs create mode 100644 MalApi.IntegrationTests/GetUserAnimeDetailsTest.cs create mode 100644 MalApi.IntegrationTests/GetUserMangaDetailsTest.cs create mode 100644 MalApi.UnitTests/MalDetailScrapingUtils.cs diff --git a/MalApi.IntegrationTests/GetMalDetails.cs b/MalApi.IntegrationTests/GetMalDetails.cs new file mode 100644 index 0000000..fdbcc0b --- /dev/null +++ b/MalApi.IntegrationTests/GetMalDetails.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using HtmlAgilityPack; + +namespace MalApi.IntegrationTests +{ + class GetMalDetails : IDisposable + { + protected static readonly string NoRedirectMalUri = "https://myanimelist.net/pressroom"; + protected static readonly string LoginUri = "https://myanimelist.net/login.php"; + + private HttpClientHandler m_httpHandler; + private HttpClient m_httpClient; + + public string UserAgent { get; set; } + + private string CsrfToken { get; set; } + + /// + /// Timeout in milliseconds for requests to MAL. Defaults to 15000 (15s). + /// + public int TimeoutInMs + { + get { return m_httpClient.Timeout.Milliseconds; } + set { m_httpClient.Timeout = TimeSpan.FromMilliseconds(value); } + } + + public GetMalDetails() + { + m_httpHandler = new HttpClientHandler() + { + AllowAutoRedirect = true, + UseCookies = true, + + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, + }; + m_httpClient = new HttpClient(m_httpHandler); + TimeoutInMs = 15 * 1000; + } + + protected HttpRequestMessage InitNewRequest(string uri, HttpMethod method) + { + HttpRequestMessage request = new HttpRequestMessage(method, uri); + + if (UserAgent != null) + { + request.Headers.TryAddWithoutValidation("User-Agent", UserAgent); + } + + return request; + } + + protected async Task ProcessRequestAsync(HttpRequestMessage request, Func processingFunc, string baseErrorMessage, CancellationToken cancellationToken) + { + try + { + // Need to read the entire content at once here because response.Content.ReadAsStringAsync doesn't support cancellation. + using (HttpResponseMessage response = await m_httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(continueOnCapturedContext: false)) + { + if (response.StatusCode == HttpStatusCode.OK) + { + var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false); + return processingFunc(responseBody); + } + throw new MalApiRequestException(string.Format("{0} Status code was {1}", baseErrorMessage, (int)response.StatusCode)); + } + } + catch (Exception ex) + { + // If we didn't read a response, then there was an error with the request/response that may be fixable with a retry. + throw new MalApiRequestException(string.Format("{0} {1}", baseErrorMessage, ex.Message), ex); + } + } + + protected string ParseCsrfTokenFromHtml(string html) + { + Match match = Regex.Match(html, @""); + if (match.Success) + { + CsrfToken = match.Groups[1].ToString(); + } + + return CsrfToken; + } + + // internal for unit testing + protected string WebFormLoginHandler(string responseBody) + { + if (responseBody.Contains("Your username or password is incorrect.")) + { + throw new MalApiRequestException("Failed to log in. Recheck credentials."); + } + + return null; + } + + public void Login(string username, string password) + { + Login(username, password, CancellationToken.None).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); + } + + private async Task Login(string username, string password, CancellationToken cancellationToken) + { + string url = NoRedirectMalUri; + + HttpRequestMessage request = InitNewRequest(url, HttpMethod.Get); + + // Get CSRF token + await ProcessRequestAsync(request, ParseCsrfTokenFromHtml, + cancellationToken: cancellationToken, + baseErrorMessage: "Failed connecting to MAL") + .ConfigureAwait(continueOnCapturedContext: false); + + // Login through the web form + url = LoginUri; + request = InitNewRequest(url, HttpMethod.Post); + + var contentPairs = new List> + { + new KeyValuePair("user_name", username), + new KeyValuePair("password", password), + new KeyValuePair("cookie", "1"), + new KeyValuePair("sublogin", "Login"), + new KeyValuePair("submit", "1"), + new KeyValuePair("csrf_token", CsrfToken) + }; + var content = new FormUrlEncodedContent(contentPairs); + request.Content = content; + + await ProcessRequestAsync(request, WebFormLoginHandler, + cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed to log in for user {0}.", username)) + .ConfigureAwait(continueOnCapturedContext: false); + } + + public void Dispose() + { + m_httpClient.Dispose(); + m_httpHandler.Dispose(); + } + } +} diff --git a/MalApi.IntegrationTests/GetMangaListForUserTest.cs b/MalApi.IntegrationTests/GetMangaListForUserTest.cs index d2cf02b..302442b 100644 --- a/MalApi.IntegrationTests/GetMangaListForUserTest.cs +++ b/MalApi.IntegrationTests/GetMangaListForUserTest.cs @@ -9,8 +9,6 @@ namespace MalApi.IntegrationTests { - // Environment variables in the Initialize method have to be set up properly - // In order for the test to succeed they need to be executed at the same (so the Environment variable can be set and used). public class GetMangaListForUserTest { [Fact] diff --git a/MalApi.IntegrationTests/GetUserAnimeDetailsTest.cs b/MalApi.IntegrationTests/GetUserAnimeDetailsTest.cs new file mode 100644 index 0000000..310f9fc --- /dev/null +++ b/MalApi.IntegrationTests/GetUserAnimeDetailsTest.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using HtmlAgilityPack; + +namespace MalApi.IntegrationTests +{ + class GetUserAnimeDetailsTest : GetMalDetails + { + private static readonly string UserAnimeDetailsUri = "https://myanimelist.net/editlist.php?type=anime&id={0}"; + + public AnimeUpdate GetUserAnimeDetailsAsync(string username, int animeId) + { + return GetUserAnimeDetailsAsync(username, animeId, CancellationToken.None).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); + } + + public async Task GetUserAnimeDetailsAsync(string username, int animeId, CancellationToken cancellationToken) + { + string url = string.Format(UserAnimeDetailsUri, animeId); + HttpRequestMessage request = InitNewRequest(url, HttpMethod.Get); + + AnimeUpdate results = await ProcessRequestAsync(request, ScrapeUserAnimeDetailsFromHtml, + cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed getting user anime details for user {0} anime ID {1}.", username, animeId)) + .ConfigureAwait(continueOnCapturedContext: false); + return results; + } + + // internal for unit testing + internal AnimeUpdate ScrapeUserAnimeDetailsFromHtml(string userAnimeDetailsHtml) + { + AnimeUpdate results = new AnimeUpdate(); + + var doc = new HtmlDocument(); + doc.LoadHtml(userAnimeDetailsHtml); + + // Episode + results.Episode = doc.GetElementbyId("add_anime_num_watched_episodes").GetAttributeValue("value", -1); + + // Status + var parentNode = doc.GetElementbyId("add_anime_status"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Status = (AnimeCompletionStatus)childNode.GetAttributeValue("value", -1); + break; + } + } + + // Enable rewatching + results.EnableRewatching = doc.GetElementbyId("add_anime_is_rewatching").Attributes["checked"] == null ? 0 : 1; + + // Score + parentNode = doc.GetElementbyId("add_anime_score"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Score = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Start date + int day = -1; + int month = -1; + int year = -1; + parentNode = doc.GetElementbyId("add_anime_start_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_start_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_start_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateStart = null; + } + else + { + results.DateStart = new DateTime(year, month, day); + } + + // Date finish + parentNode = doc.GetElementbyId("add_anime_finish_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_finish_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_finish_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateFinish = null; + } + else + { + results.DateFinish = new DateTime(year, month, day); + } + + // Tags + results.Tags = doc.GetElementbyId("add_anime_tags").InnerText; + + // Priority + parentNode = doc.GetElementbyId("add_anime_priority"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Priority = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Storage type + parentNode = doc.GetElementbyId("add_anime_storage_type"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.StorageType = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Storage value + results.StorageValue = doc.GetElementbyId("add_anime_storage_value").GetAttributeValue("value", -1); + + // Times rewatched + results.TimesRewatched = doc.GetElementbyId("add_anime_num_watched_times").GetAttributeValue("value", -1); + + // Rewatch value + parentNode = doc.GetElementbyId("add_anime_rewatch_value"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.RewatchValue = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Comments + results.Comments = doc.GetElementbyId("add_anime_comments").InnerText; + + // Enable discussion + parentNode = doc.GetElementbyId("add_anime_is_asked_to_discuss"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + // Because 'Enable discussion = 1' sent for update sets the first options of the dropdown, which corresponds to 0 and vice versa... + int temp = childNode.GetAttributeValue("value", -1); + temp = temp == 1 ? 0 : 1; + results.EnableDiscussion = temp; + break; + } + } + + return results; + } + } +} diff --git a/MalApi.IntegrationTests/GetUserMangaDetailsTest.cs b/MalApi.IntegrationTests/GetUserMangaDetailsTest.cs new file mode 100644 index 0000000..671bdba --- /dev/null +++ b/MalApi.IntegrationTests/GetUserMangaDetailsTest.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using HtmlAgilityPack; + +namespace MalApi.IntegrationTests +{ + class GetUserMangaDetailsTest : GetMalDetails + { + private static readonly string UserMangaDetailsUri = "https://myanimelist.net/panel.php?go=editmanga&id={0}"; + + public MangaUpdate GetUserMangaDetailsAsync(string username, int mangaId) + { + return GetUserMangaDetailsAsync(username, mangaId, CancellationToken.None).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); + } + + public async Task GetUserMangaDetailsAsync(string username, int mangaId, CancellationToken cancellationToken) + { + string url = string.Format(UserMangaDetailsUri, mangaId); + HttpRequestMessage request = InitNewRequest(url, HttpMethod.Get); + + MangaUpdate results = await ProcessRequestAsync(request, ScrapeUserMangaDetailsFromHtml, + cancellationToken: cancellationToken, + baseErrorMessage: string.Format("Failed getting user manga details for user {0} manga ID {1}.", username, mangaId)) + .ConfigureAwait(continueOnCapturedContext: false); + return results; + } + + // internal for unit testing + internal MangaUpdate ScrapeUserMangaDetailsFromHtml(string userMangaDetailsHtml) + { + MangaUpdate results = new MangaUpdate(); + + var doc = new HtmlDocument(); + doc.LoadHtml(userMangaDetailsHtml); + + // Chapter + results.Chapter = doc.GetElementbyId("add_manga_num_read_chapters").GetAttributeValue("value", -1); + + // Volume + results.Volume = doc.GetElementbyId("add_manga_num_read_volumes").GetAttributeValue("value", -1); + + // Status + var parentNode = doc.GetElementbyId("add_manga_status"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Status = (MangaCompletionStatus)childNode.GetAttributeValue("value", -1); + break; + } + } + + // Enable rereading + results.EnableRereading = doc.GetElementbyId("add_manga_is_rereading").Attributes["checked"] == null ? 0 : 1; + + // Score + parentNode = doc.GetElementbyId("add_manga_score"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Score = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Start date + int day = -1; + int month = -1; + int year = -1; + parentNode = doc.GetElementbyId("add_manga_start_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_start_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_start_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateStart = null; + } + else + { + results.DateStart = new DateTime(year, month, day); + } + + // Date finish + parentNode = doc.GetElementbyId("add_manga_finish_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_finish_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_finish_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateFinish = null; + } + else + { + results.DateFinish = new DateTime(year, month, day); + } + + // Tags + results.Tags = doc.GetElementbyId("add_manga_tags").InnerText; + + // Priority + parentNode = doc.GetElementbyId("add_manga_priority"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Priority = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Times reread + results.TimesReread = doc.GetElementbyId("add_manga_num_read_times").GetAttributeValue("value", -1); + + // Reread value + parentNode = doc.GetElementbyId("add_manga_reread_value"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.RereadValue = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Comments + results.Comments = doc.GetElementbyId("add_manga_comments").InnerText; + + // Enable discussion + parentNode = doc.GetElementbyId("add_manga_is_asked_to_discuss"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + // Because 'Enable discussion = 1' sent for update sets the first options of the dropdown, which corresponds to 0 and vice versa... + int temp = childNode.GetAttributeValue("value", -1); + temp = temp == 1 ? 0 : 1; + results.EnableDiscussion = temp; + break; + } + } + + return results; + } + + } +} diff --git a/MalApi.IntegrationTests/MalApi.IntegrationTests.csproj b/MalApi.IntegrationTests/MalApi.IntegrationTests.csproj index c127efd..c985f9a 100644 --- a/MalApi.IntegrationTests/MalApi.IntegrationTests.csproj +++ b/MalApi.IntegrationTests/MalApi.IntegrationTests.csproj @@ -11,10 +11,11 @@ + - - + + diff --git a/MalApi.IntegrationTests/UpdateUserAnimeTest.cs b/MalApi.IntegrationTests/UpdateUserAnimeTest.cs index 4b70504..e3e5e0d 100644 --- a/MalApi.IntegrationTests/UpdateUserAnimeTest.cs +++ b/MalApi.IntegrationTests/UpdateUserAnimeTest.cs @@ -8,8 +8,6 @@ namespace MalApi.IntegrationTests { - // Environment variables in the Initialize method have to be set up properly - // In order for the test to succeed they need to be executed at the same (so the Environment variable can be set and used). public class UpdateUserAnimeTest { [Fact] @@ -59,63 +57,68 @@ public void UpdateAnimeForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, baseInfo, username, password); - Assert.Equal("Updated", result); - - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); - - // Assert first update against base info - Assert.Equal(baseInfo.Episode, baseReults.Episode); - Assert.Equal(baseInfo.Status, baseReults.Status); - Assert.Equal(baseInfo.Score, baseReults.Score); - Assert.Equal(baseInfo.StorageType, baseReults.StorageType); - Assert.Equal(baseInfo.StorageValue, baseReults.StorageValue); - Assert.Equal(baseInfo.TimesRewatched, baseReults.TimesRewatched); - Assert.Equal(baseInfo.RewatchValue, baseReults.RewatchValue); - Assert.Equal(baseInfo.DateStart, baseReults.DateStart); - Assert.Equal(baseInfo.DateFinish, baseReults.DateFinish); - Assert.Equal(baseInfo.Priority, baseReults.Priority); - Assert.Equal(baseInfo.EnableDiscussion, baseReults.EnableDiscussion); - Assert.Equal(baseInfo.EnableRewatching, baseReults.EnableRewatching); - Assert.Equal(baseInfo.Comments, baseReults.Comments); - Assert.Equal(baseInfo.Tags, baseReults.Tags); - - result = api.UpdateAnimeForUser(animeId, updateInfo, username, password); - Assert.Equal("Updated", result); - - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); - - // Assert second update with update info - Assert.Equal(updateInfo.Episode, updatedResults.Episode); - Assert.Equal(updateInfo.Status, updatedResults.Status); - Assert.Equal(updateInfo.Score, updatedResults.Score); - Assert.Equal(updateInfo.StorageType, updatedResults.StorageType); - Assert.Equal(updateInfo.StorageValue, updatedResults.StorageValue); - Assert.Equal(updateInfo.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(updateInfo.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(updateInfo.DateStart, updatedResults.DateStart); - Assert.Equal(updateInfo.DateFinish, updatedResults.DateFinish); - Assert.Equal(updateInfo.Priority, updatedResults.Priority); - Assert.Equal(updateInfo.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(updateInfo.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(updateInfo.Comments, updatedResults.Comments); - Assert.Equal(updateInfo.Tags, updatedResults.Tags); - - // Assert all values have been changed - Assert.NotEqual(baseReults.Episode, updatedResults.Episode); - Assert.NotEqual(baseReults.Status, updatedResults.Status); - Assert.NotEqual(baseReults.Score, updatedResults.Score); - Assert.NotEqual(baseReults.StorageType, updatedResults.StorageType); - Assert.NotEqual(baseReults.StorageValue, updatedResults.StorageValue); - Assert.NotEqual(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.NotEqual(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); - Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); - Assert.NotEqual(baseReults.Priority, updatedResults.Priority); - Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.NotEqual(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.NotEqual(baseReults.Comments, updatedResults.Comments); - Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); + + string result = api.UpdateAnimeForUser(animeId, baseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); + + // Assert first update against base info + Assert.Equal(baseInfo.Episode, baseReults.Episode); + Assert.Equal(baseInfo.Status, baseReults.Status); + Assert.Equal(baseInfo.Score, baseReults.Score); + Assert.Equal(baseInfo.StorageType, baseReults.StorageType); + Assert.Equal(baseInfo.StorageValue, baseReults.StorageValue); + Assert.Equal(baseInfo.TimesRewatched, baseReults.TimesRewatched); + Assert.Equal(baseInfo.RewatchValue, baseReults.RewatchValue); + Assert.Equal(baseInfo.DateStart, baseReults.DateStart); + Assert.Equal(baseInfo.DateFinish, baseReults.DateFinish); + Assert.Equal(baseInfo.Priority, baseReults.Priority); + Assert.Equal(baseInfo.EnableDiscussion, baseReults.EnableDiscussion); + Assert.Equal(baseInfo.EnableRewatching, baseReults.EnableRewatching); + Assert.Equal(baseInfo.Comments, baseReults.Comments); + Assert.Equal(baseInfo.Tags, baseReults.Tags); + + result = api.UpdateAnimeForUser(animeId, updateInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); + + // Assert second update with update info + Assert.Equal(updateInfo.Episode, updatedResults.Episode); + Assert.Equal(updateInfo.Status, updatedResults.Status); + Assert.Equal(updateInfo.Score, updatedResults.Score); + Assert.Equal(updateInfo.StorageType, updatedResults.StorageType); + Assert.Equal(updateInfo.StorageValue, updatedResults.StorageValue); + Assert.Equal(updateInfo.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(updateInfo.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(updateInfo.DateStart, updatedResults.DateStart); + Assert.Equal(updateInfo.DateFinish, updatedResults.DateFinish); + Assert.Equal(updateInfo.Priority, updatedResults.Priority); + Assert.Equal(updateInfo.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(updateInfo.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(updateInfo.Comments, updatedResults.Comments); + Assert.Equal(updateInfo.Tags, updatedResults.Tags); + + // Assert all values have been changed + Assert.NotEqual(baseReults.Episode, updatedResults.Episode); + Assert.NotEqual(baseReults.Status, updatedResults.Status); + Assert.NotEqual(baseReults.Score, updatedResults.Score); + Assert.NotEqual(baseReults.StorageType, updatedResults.StorageType); + Assert.NotEqual(baseReults.StorageValue, updatedResults.StorageValue); + Assert.NotEqual(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.NotEqual(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); + Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); + Assert.NotEqual(baseReults.Priority, updatedResults.Priority); + Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.NotEqual(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.NotEqual(baseReults.Comments, updatedResults.Comments); + Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + } } } @@ -140,38 +143,43 @@ public void UpdateAnimeEpisodeForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); - // Assert first update against base info - Assert.Equal(partialBaseInfo.Episode, baseReults.Episode); + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); + // Assert first update against base info + Assert.Equal(partialBaseInfo.Episode, baseReults.Episode); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Episode, updatedResults.Episode); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert that only the episode has been changed - Assert.NotEqual(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Episode, updatedResults.Episode); + + // Assert that only the episode has been changed + Assert.NotEqual(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -196,38 +204,43 @@ public void UpdateAnimeStatusForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.Status, baseReults.Status); + // Assert first update against base info + Assert.Equal(partialBaseInfo.Status, baseReults.Status); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Status, updatedResults.Status); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Status, updatedResults.Status); - // Assert that only the status has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.NotEqual(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the status has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.NotEqual(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -252,38 +265,43 @@ public void UpdateAnimeScoreForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); + + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.Score, baseReults.Score); + // Assert first update against base info + Assert.Equal(partialBaseInfo.Score, baseReults.Score); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Score, updatedResults.Score); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Score, updatedResults.Score); - // Assert that only the score has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.NotEqual(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the score has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.NotEqual(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -308,38 +326,43 @@ public void UpdateAnimeStorageTypeForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); + + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.StorageType, baseReults.StorageType); + // Assert first update against base info + Assert.Equal(partialBaseInfo.StorageType, baseReults.StorageType); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.StorageType, updatedResults.StorageType); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.StorageType, updatedResults.StorageType); - // Assert that only the storage type has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.NotEqual(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the storage type has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.NotEqual(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -364,38 +387,43 @@ public void UpdateAnimeStorageValueForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.StorageValue, baseReults.StorageValue); + // Assert first update against base info + Assert.Equal(partialBaseInfo.StorageValue, baseReults.StorageValue); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.StorageValue, updatedResults.StorageValue); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.StorageValue, updatedResults.StorageValue); - // Assert that only the storage value has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.NotEqual(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the storage value has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.NotEqual(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -420,38 +448,43 @@ public void UpdateAnimeTimesRewatchedForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); + + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.TimesRewatched, baseReults.TimesRewatched); + // Assert first update against base info + Assert.Equal(partialBaseInfo.TimesRewatched, baseReults.TimesRewatched); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.TimesRewatched, updatedResults.TimesRewatched); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.TimesRewatched, updatedResults.TimesRewatched); - // Assert that only the times rewatched has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.NotEqual(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the times rewatched has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.NotEqual(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -476,38 +509,43 @@ public void UpdateAnimeRewatchValueForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); + + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.RewatchValue, baseReults.RewatchValue); + // Assert first update against base info + Assert.Equal(partialBaseInfo.RewatchValue, baseReults.RewatchValue); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.RewatchValue, updatedResults.RewatchValue); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.RewatchValue, updatedResults.RewatchValue); - // Assert that only the rewatch value has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.NotEqual(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the rewatch value has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.NotEqual(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -532,38 +570,43 @@ public void UpdateAnimeDateStartForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.DateStart, baseReults.DateStart); + // Assert first update against base info + Assert.Equal(partialBaseInfo.DateStart, baseReults.DateStart); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.DateStart, updatedResults.DateStart); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.DateStart, updatedResults.DateStart); - // Assert that only the date start has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the date start has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -577,7 +620,7 @@ public void UpdateAnimeDateFinishForUserTest() int animeId = 1; AnimeUpdate partialBaseInfo = new AnimeUpdate() - { + { DateFinish = new DateTime(2017, 10, 5) }; @@ -588,38 +631,43 @@ public void UpdateAnimeDateFinishForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); + + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.DateFinish, baseReults.DateFinish); + // Assert first update against base info + Assert.Equal(partialBaseInfo.DateFinish, baseReults.DateFinish); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.DateFinish, updatedResults.DateFinish); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.DateFinish, updatedResults.DateFinish); - // Assert that only the date finish has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the date finish has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -644,38 +692,43 @@ public void UpdateAnimePriorityForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.Priority, baseReults.Priority); + // Assert first update against base info + Assert.Equal(partialBaseInfo.Priority, baseReults.Priority); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Priority, updatedResults.Priority); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Priority, updatedResults.Priority); - // Assert that only the priority has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.NotEqual(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the priority has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.NotEqual(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -700,38 +753,43 @@ public void UpdateAnimeEnableDiscussionForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); + + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.EnableDiscussion, baseReults.EnableDiscussion); + // Assert first update against base info + Assert.Equal(partialBaseInfo.EnableDiscussion, baseReults.EnableDiscussion); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.EnableDiscussion, updatedResults.EnableDiscussion); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.EnableDiscussion, updatedResults.EnableDiscussion); - // Assert that only the enable discussion has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the enable discussion has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -756,38 +814,43 @@ public void UpdateAnimeEnableRewatchingForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); - // Assert first update against base info - Assert.Equal(partialBaseInfo.EnableRewatching, baseReults.EnableRewatching); + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); + // Assert first update against base info + Assert.Equal(partialBaseInfo.EnableRewatching, baseReults.EnableRewatching); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.EnableRewatching, updatedResults.EnableRewatching); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert that only the enable rewatching has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.NotEqual(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.EnableRewatching, updatedResults.EnableRewatching); + + // Assert that only the enable rewatching has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.NotEqual(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -812,38 +875,43 @@ public void UpdateAnimeCommentsForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.Comments, baseReults.Comments); + // Assert first update against base info + Assert.Equal(partialBaseInfo.Comments, baseReults.Comments); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Comments, updatedResults.Comments); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Comments, updatedResults.Comments); - // Assert that only the comments has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.NotEqual(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + // Assert that only the comments has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.NotEqual(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -868,38 +936,43 @@ public void UpdateAnimeTagsForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + helper.Login(username, password); + + string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate baseReults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert first update against base info - Assert.Equal(partialBaseInfo.Tags, baseReults.Tags); + // Assert first update against base info + Assert.Equal(partialBaseInfo.Tags, baseReults.Tags); - result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); + result = api.UpdateAnimeForUser(animeId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); - AnimeUpdate updatedResults = api.GetUserAnimeDetails(username, password, animeId); + AnimeUpdate updatedResults = helper.GetUserAnimeDetailsAsync(username, animeId); - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Tags, updatedResults.Tags); + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Tags, updatedResults.Tags); - // Assert that only the tags has been changed - Assert.Equal(baseReults.Episode, updatedResults.Episode); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.StorageType, updatedResults.StorageType); - Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); - Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); - Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + // Assert that only the tags has been changed + Assert.Equal(baseReults.Episode, updatedResults.Episode); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.StorageType, updatedResults.StorageType); + Assert.Equal(baseReults.StorageValue, updatedResults.StorageValue); + Assert.Equal(baseReults.TimesRewatched, updatedResults.TimesRewatched); + Assert.Equal(baseReults.RewatchValue, updatedResults.RewatchValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRewatching, updatedResults.EnableRewatching); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + } } } @@ -933,7 +1006,8 @@ public void GetAnimeListForUserCanceled() using (MyAnimeListApi api = new MyAnimeListApi()) { CancellationTokenSource tokenSource = new CancellationTokenSource(); - Task userLookupTask = api.UpdateAnimeForUserAsync(animeId, updateInfo, username, password, tokenSource.Token); + Task userLookupTask = + api.UpdateAnimeForUserAsync(animeId, updateInfo, username, password, tokenSource.Token); tokenSource.Cancel(); Assert.Throws(() => userLookupTask.GetAwaiter().GetResult()); } @@ -954,32 +1028,61 @@ public void IncorrectUsernameAnimeEpisodeUpdateTest() Episode = 1 }; - AnimeUpdate partialUpdateInfo = new AnimeUpdate() + using (MyAnimeListApi api = new MyAnimeListApi()) { - Episode = 26 + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) + { + Assert.Throws(() => helper.Login(username, password)); + + Assert.Throws(() => api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password)); + } + } + } + + [Fact] + public void WrongAnimeIdUpdateTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); + + int animeId = 2; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + Episode = 1 }; using (MyAnimeListApi api = new MyAnimeListApi()) { - try + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) { - string result = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); + helper.Login(username, password); + Assert.Throws(() => api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password)); } - catch (Exception ex) - { - Assert.Equal(typeof(MalApiRequestException), ex.GetType()); - } + } + } - try - { - AnimeUpdate baseReults = api.GetUserAnimeDetails(username, password, animeId); + [Fact] + public void TestTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); - } - catch (Exception ex) + int animeId = 7; + + AnimeUpdate partialBaseInfo = new AnimeUpdate() + { + Episode = 1 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + using (GetUserAnimeDetailsTest helper = new GetUserAnimeDetailsTest()) { - Assert.Equal(typeof(MalApiRequestException), ex.GetType()); - Assert.Equal("Failed to log in. Recheck credentials.", ex.Message); + helper.Login(username, password); + + string test = api.UpdateAnimeForUser(animeId, partialBaseInfo, username, password); } } } diff --git a/MalApi.IntegrationTests/UpdateUserMangaTest.cs b/MalApi.IntegrationTests/UpdateUserMangaTest.cs index 6af21fb..10dc027 100644 --- a/MalApi.IntegrationTests/UpdateUserMangaTest.cs +++ b/MalApi.IntegrationTests/UpdateUserMangaTest.cs @@ -8,8 +8,6 @@ namespace MalApi.IntegrationTests { - // Environment variables in the Initialize method have to be set up properly - // In order for the test to succeed they need to be executed at the same (so the Environment variable can be set and used). public class UpdateUserMangaTest { [Fact] @@ -59,60 +57,66 @@ public void UpdateMangaForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, baseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(baseInfo.Chapter, baseReults.Chapter); - Assert.Equal(baseInfo.Volume, baseReults.Volume); - Assert.Equal(baseInfo.Status, baseReults.Status); - Assert.Equal(baseInfo.Score, baseReults.Score); - Assert.Equal(baseInfo.TimesReread, baseReults.TimesReread); - Assert.Equal(baseInfo.RereadValue, baseReults.RereadValue); - Assert.Equal(baseInfo.DateStart, baseReults.DateStart); - Assert.Equal(baseInfo.DateFinish, baseReults.DateFinish); - Assert.Equal(baseInfo.Priority, baseReults.Priority); - Assert.Equal(baseInfo.EnableDiscussion, baseReults.EnableDiscussion); - Assert.Equal(baseInfo.EnableRereading, baseReults.EnableRereading); - Assert.Equal(baseInfo.Comments, baseReults.Comments); - Assert.Equal(baseInfo.Tags, baseReults.Tags); - - result = api.UpdateMangaForUser(mangaId, updateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(updateInfo.Chapter, updatedResults.Chapter); - Assert.Equal(updateInfo.Volume, updatedResults.Volume); - Assert.Equal(updateInfo.Status, updatedResults.Status); - Assert.Equal(updateInfo.Score, updatedResults.Score); - Assert.Equal(updateInfo.TimesReread, updatedResults.TimesReread); - Assert.Equal(updateInfo.RereadValue, updatedResults.RereadValue); - Assert.Equal(updateInfo.DateStart, updatedResults.DateStart); - Assert.Equal(updateInfo.DateFinish, updatedResults.DateFinish); - Assert.Equal(updateInfo.Priority, updatedResults.Priority); - Assert.Equal(updateInfo.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(updateInfo.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(updateInfo.Comments, updatedResults.Comments); - Assert.Equal(updateInfo.Tags, updatedResults.Tags); - - // Assert all values have been changed - Assert.NotEqual(baseReults.Chapter, updatedResults.Chapter); - Assert.NotEqual(baseReults.Volume, updatedResults.Volume); - Assert.NotEqual(baseReults.Status, updatedResults.Status); - Assert.NotEqual(baseReults.Score, updatedResults.Score); - Assert.NotEqual(baseReults.TimesReread, updatedResults.TimesReread); - Assert.NotEqual(baseReults.RereadValue, updatedResults.RereadValue); - Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); - Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); - Assert.NotEqual(baseReults.Priority, updatedResults.Priority); - Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.NotEqual(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.NotEqual(baseReults.Comments, updatedResults.Comments); - Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); + + string result = api.UpdateMangaForUser(mangaId, baseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(baseInfo.Chapter, baseReults.Chapter); + Assert.Equal(baseInfo.Volume, baseReults.Volume); + Assert.Equal(baseInfo.Status, baseReults.Status); + Assert.Equal(baseInfo.Score, baseReults.Score); + Assert.Equal(baseInfo.TimesReread, baseReults.TimesReread); + Assert.Equal(baseInfo.RereadValue, baseReults.RereadValue); + Assert.Equal(baseInfo.DateStart, baseReults.DateStart); + Assert.Equal(baseInfo.DateFinish, baseReults.DateFinish); + Assert.Equal(baseInfo.Priority, baseReults.Priority); + Assert.Equal(baseInfo.EnableDiscussion, baseReults.EnableDiscussion); + Assert.Equal(baseInfo.EnableRereading, baseReults.EnableRereading); + Assert.Equal(baseInfo.Comments, baseReults.Comments); + Assert.Equal(baseInfo.Tags, baseReults.Tags); + + result = api.UpdateMangaForUser(mangaId, updateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(updateInfo.Chapter, updatedResults.Chapter); + Assert.Equal(updateInfo.Volume, updatedResults.Volume); + Assert.Equal(updateInfo.Status, updatedResults.Status); + Assert.Equal(updateInfo.Score, updatedResults.Score); + Assert.Equal(updateInfo.TimesReread, updatedResults.TimesReread); + Assert.Equal(updateInfo.RereadValue, updatedResults.RereadValue); + Assert.Equal(updateInfo.DateStart, updatedResults.DateStart); + Assert.Equal(updateInfo.DateFinish, updatedResults.DateFinish); + Assert.Equal(updateInfo.Priority, updatedResults.Priority); + Assert.Equal(updateInfo.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(updateInfo.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(updateInfo.Comments, updatedResults.Comments); + Assert.Equal(updateInfo.Tags, updatedResults.Tags); + + // Assert all values have been changed + Assert.NotEqual(baseReults.Chapter, updatedResults.Chapter); + Assert.NotEqual(baseReults.Volume, updatedResults.Volume); + Assert.NotEqual(baseReults.Status, updatedResults.Status); + Assert.NotEqual(baseReults.Score, updatedResults.Score); + Assert.NotEqual(baseReults.TimesReread, updatedResults.TimesReread); + Assert.NotEqual(baseReults.RereadValue, updatedResults.RereadValue); + Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); + Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); + Assert.NotEqual(baseReults.Priority, updatedResults.Priority); + Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.NotEqual(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.NotEqual(baseReults.Comments, updatedResults.Comments); + Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + + } } } @@ -137,36 +141,41 @@ public void UpdateMangaChapterForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.Chapter, baseReults.Chapter); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Chapter, updatedResults.Chapter); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the chapter has been changed - Assert.NotEqual(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Chapter, baseReults.Chapter); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Chapter, updatedResults.Chapter); + + // Assert that only the chapter has been changed + Assert.NotEqual(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -191,36 +200,41 @@ public void UpdateMangaVolumeForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.Volume, baseReults.Volume); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Volume, updatedResults.Volume); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the volume has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.NotEqual(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Volume, baseReults.Volume); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Volume, updatedResults.Volume); + + // Assert that only the volume has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.NotEqual(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -245,36 +259,41 @@ public void UpdateMangaStatusForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.Status, baseReults.Status); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Status, updatedResults.Status); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the status has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.NotEqual(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Status, baseReults.Status); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Status, updatedResults.Status); + + // Assert that only the status has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.NotEqual(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -299,36 +318,41 @@ public void UpdateMangaScoreForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.Score, baseReults.Score); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Score, updatedResults.Score); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the score has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.NotEqual(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Score, baseReults.Score); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Score, updatedResults.Score); + + // Assert that only the score has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.NotEqual(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -353,36 +377,41 @@ public void UpdateMangaTimesRereadForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.TimesReread, baseReults.TimesReread); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.TimesReread, updatedResults.TimesReread); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the times reread has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.NotEqual(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.TimesReread, baseReults.TimesReread); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.TimesReread, updatedResults.TimesReread); + + // Assert that only the times reread has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.NotEqual(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -407,36 +436,41 @@ public void UpdateMangaRereadValueForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.RereadValue, baseReults.RereadValue); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.RereadValue, updatedResults.RereadValue); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the rearead value has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.NotEqual(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.RereadValue, baseReults.RereadValue); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.RereadValue, updatedResults.RereadValue); + + // Assert that only the rearead value has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.NotEqual(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -461,36 +495,41 @@ public void UpdateMangaDateStartForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.DateStart, baseReults.DateStart); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.DateStart, updatedResults.DateStart); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the date start has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.DateStart, baseReults.DateStart); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.DateStart, updatedResults.DateStart); + + // Assert that only the date start has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.NotEqual(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -515,36 +554,41 @@ public void UpdateMangaDateFinishForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.DateFinish, baseReults.DateFinish); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.DateFinish, updatedResults.DateFinish); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the date finish has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.DateFinish, baseReults.DateFinish); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.DateFinish, updatedResults.DateFinish); + + // Assert that only the date finish has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.NotEqual(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -569,36 +613,41 @@ public void UpdateMangaPriorityForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.Priority, baseReults.Priority); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Priority, updatedResults.Priority); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the priority has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.NotEqual(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Priority, baseReults.Priority); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Priority, updatedResults.Priority); + + // Assert that only the priority has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.NotEqual(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -623,36 +672,41 @@ public void UpdateMangaEnableDiscussionForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.EnableDiscussion, baseReults.EnableDiscussion); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.EnableDiscussion, updatedResults.EnableDiscussion); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the enable discussion has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.EnableDiscussion, baseReults.EnableDiscussion); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.EnableDiscussion, updatedResults.EnableDiscussion); + + // Assert that only the enable discussion has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.NotEqual(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -677,36 +731,41 @@ public void UpdateMangaEnableRereadingForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.EnableRereading, baseReults.EnableRereading); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.EnableRereading, updatedResults.EnableRereading); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the enable rereading has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.NotEqual(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.EnableRereading, baseReults.EnableRereading); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.EnableRereading, updatedResults.EnableRereading); + + // Assert that only the enable rereading has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.NotEqual(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -731,36 +790,41 @@ public void UpdateMangaCommentsorUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.Comments, baseReults.Comments); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Comments, updatedResults.Comments); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the comments has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.NotEqual(baseReults.Comments, updatedResults.Comments); - Assert.Equal(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Comments, baseReults.Comments); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Comments, updatedResults.Comments); + + // Assert that only the comments has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.NotEqual(baseReults.Comments, updatedResults.Comments); + Assert.Equal(baseReults.Tags, updatedResults.Tags); + } } } @@ -785,36 +849,41 @@ public void UpdateMangaTagsForUserTest() using (MyAnimeListApi api = new MyAnimeListApi()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert first update against base info - Assert.Equal(partialBaseInfo.Tags, baseReults.Tags); - - result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); - Assert.Equal("Updated", result); - - MangaUpdate updatedResults = api.GetUserMangaDetails(username, password, mangaId); - - // Assert second update with update info - Assert.Equal(partialUpdateInfo.Tags, updatedResults.Tags); + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) + { + helper.Login(username, password); - // Assert that only the tags has been changed - Assert.Equal(baseReults.Chapter, updatedResults.Chapter); - Assert.Equal(baseReults.Volume, updatedResults.Volume); - Assert.Equal(baseReults.Status, updatedResults.Status); - Assert.Equal(baseReults.Score, updatedResults.Score); - Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); - Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); - Assert.Equal(baseReults.DateStart, updatedResults.DateStart); - Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); - Assert.Equal(baseReults.Priority, updatedResults.Priority); - Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); - Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); - Assert.Equal(baseReults.Comments, updatedResults.Comments); - Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate baseReults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert first update against base info + Assert.Equal(partialBaseInfo.Tags, baseReults.Tags); + + result = api.UpdateMangaForUser(mangaId, partialUpdateInfo, username, password); + Assert.Equal("Updated", result); + + MangaUpdate updatedResults = helper.GetUserMangaDetailsAsync(username, mangaId); + + // Assert second update with update info + Assert.Equal(partialUpdateInfo.Tags, updatedResults.Tags); + + // Assert that only the tags has been changed + Assert.Equal(baseReults.Chapter, updatedResults.Chapter); + Assert.Equal(baseReults.Volume, updatedResults.Volume); + Assert.Equal(baseReults.Status, updatedResults.Status); + Assert.Equal(baseReults.Score, updatedResults.Score); + Assert.Equal(baseReults.TimesReread, updatedResults.TimesReread); + Assert.Equal(baseReults.RereadValue, updatedResults.RereadValue); + Assert.Equal(baseReults.DateStart, updatedResults.DateStart); + Assert.Equal(baseReults.DateFinish, updatedResults.DateFinish); + Assert.Equal(baseReults.Priority, updatedResults.Priority); + Assert.Equal(baseReults.EnableDiscussion, updatedResults.EnableDiscussion); + Assert.Equal(baseReults.EnableRereading, updatedResults.EnableRereading); + Assert.Equal(baseReults.Comments, updatedResults.Comments); + Assert.NotEqual(baseReults.Tags, updatedResults.Tags); + } } } @@ -848,7 +917,8 @@ public void UpdateMangaForUserCanceled() using (MyAnimeListApi api = new MyAnimeListApi()) { CancellationTokenSource tokenSource = new CancellationTokenSource(); - Task userLookupTask = api.UpdateMangaForUserAsync(mangaId, updateInfo, username, password, tokenSource.Token); + Task userLookupTask = + api.UpdateMangaForUserAsync(mangaId, updateInfo, username, password, tokenSource.Token); tokenSource.Cancel(); Assert.Throws(() => userLookupTask.GetAwaiter().GetResult()); } @@ -869,32 +939,37 @@ public void IncorrectUsernameMangaChapterUpdateTest() Chapter = 1 }; - MangaUpdate partialUpdateInfo = new MangaUpdate() - { - Chapter = 162 - }; - using (MyAnimeListApi api = new MyAnimeListApi()) { - try + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) { - string result = api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password); + Assert.Throws(() => helper.Login(username, password)); + Assert.Throws(() => api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password)); } - catch (Exception ex) - { - Assert.Equal(typeof(MalApiRequestException), ex.GetType()); - } + } + } - try - { - MangaUpdate baseReults = api.GetUserMangaDetails(username, password, mangaId); + [Fact] + public void WrongMangaIdUpdateTest() + { + string username = System.Environment.GetEnvironmentVariable("MAL_USERNAME"); + string password = System.Environment.GetEnvironmentVariable("MAL_PASSWORD"); - } - catch (Exception ex) + int mangaId = 5; + + MangaUpdate partialBaseInfo = new MangaUpdate() + { + Chapter = 1 + }; + + using (MyAnimeListApi api = new MyAnimeListApi()) + { + using (GetUserMangaDetailsTest helper = new GetUserMangaDetailsTest()) { - Assert.Equal(typeof(MalApiRequestException), ex.GetType()); - Assert.Equal("Failed to log in. Recheck credentials.", ex.Message); + helper.Login(username, password); + + Assert.Throws(() => api.UpdateMangaForUser(mangaId, partialBaseInfo, username, password)); } } } diff --git a/MalApi.IntegrationTests/readme.txt b/MalApi.IntegrationTests/readme.txt index 94b8228..d195066 100644 --- a/MalApi.IntegrationTests/readme.txt +++ b/MalApi.IntegrationTests/readme.txt @@ -10,3 +10,5 @@ Steps to set up environmental variables: 2) Add two new user variables called 'MAL_USERNAME' and 'MAL_PASSWORD' with the appropriate values for the account you wish to be used with these tests. 3) Done! Go run the tests and see if everything's OK. + +If the scraping methods in the integration test project are changed (ScrapeUserAnimeDetailsFromHtml and ScrapeUserMangaDetailsFromHtml) be sure to also update them in the unit test project (MalDetailScrapingUtils.cs). diff --git a/MalApi.UnitTests/MalApi.UnitTests.csproj b/MalApi.UnitTests/MalApi.UnitTests.csproj index 51caa38..62fc469 100644 --- a/MalApi.UnitTests/MalApi.UnitTests.csproj +++ b/MalApi.UnitTests/MalApi.UnitTests.csproj @@ -20,10 +20,11 @@ + - - + + diff --git a/MalApi.UnitTests/MalDetailScrapingUtils.cs b/MalApi.UnitTests/MalDetailScrapingUtils.cs new file mode 100644 index 0000000..8964797 --- /dev/null +++ b/MalApi.UnitTests/MalDetailScrapingUtils.cs @@ -0,0 +1,349 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HtmlAgilityPack; + +namespace MalApi.UnitTests +{ + class MalDetailScrapingUtils + { + public static AnimeUpdate ScrapeUserAnimeDetailsFromHtml(string userAnimeDetailsHtml) + { + AnimeUpdate results = new AnimeUpdate(); + + var doc = new HtmlDocument(); + doc.LoadHtml(userAnimeDetailsHtml); + + // Episode + results.Episode = doc.GetElementbyId("add_anime_num_watched_episodes").GetAttributeValue("value", -1); + + // Status + var parentNode = doc.GetElementbyId("add_anime_status"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Status = (AnimeCompletionStatus)childNode.GetAttributeValue("value", -1); + break; + } + } + + // Enable rewatching + results.EnableRewatching = doc.GetElementbyId("add_anime_is_rewatching").Attributes["checked"] == null ? 0 : 1; + + // Score + parentNode = doc.GetElementbyId("add_anime_score"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Score = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Start date + int day = -1; + int month = -1; + int year = -1; + parentNode = doc.GetElementbyId("add_anime_start_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_start_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_start_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateStart = null; + } + else + { + results.DateStart = new DateTime(year, month, day); + } + + // Date finish + parentNode = doc.GetElementbyId("add_anime_finish_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_finish_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_anime_finish_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateFinish = null; + } + else + { + results.DateFinish = new DateTime(year, month, day); + } + + // Tags + results.Tags = doc.GetElementbyId("add_anime_tags").InnerText; + + // Priority + parentNode = doc.GetElementbyId("add_anime_priority"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Priority = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Storage type + parentNode = doc.GetElementbyId("add_anime_storage_type"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.StorageType = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Storage value + results.StorageValue = doc.GetElementbyId("add_anime_storage_value").GetAttributeValue("value", -1); + + // Times rewatched + results.TimesRewatched = doc.GetElementbyId("add_anime_num_watched_times").GetAttributeValue("value", -1); + + // Rewatch value + parentNode = doc.GetElementbyId("add_anime_rewatch_value"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.RewatchValue = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Comments + results.Comments = doc.GetElementbyId("add_anime_comments").InnerText; + + // Enable discussion + parentNode = doc.GetElementbyId("add_anime_is_asked_to_discuss"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + // Because 'Enable discussion = 1' sent for update sets the first options of the dropdown, which corresponds to 0 and vice versa... + int temp = childNode.GetAttributeValue("value", -1); + temp = temp == 1 ? 0 : 1; + results.EnableDiscussion = temp; + break; + } + } + + return results; + } + + public static MangaUpdate ScrapeUserMangaDetailsFromHtml(string userMangaDetailsHtml) + { + MangaUpdate results = new MangaUpdate(); + + var doc = new HtmlDocument(); + doc.LoadHtml(userMangaDetailsHtml); + + // Chapter + results.Chapter = doc.GetElementbyId("add_manga_num_read_chapters").GetAttributeValue("value", -1); + + // Volume + results.Volume = doc.GetElementbyId("add_manga_num_read_volumes").GetAttributeValue("value", -1); + + // Status + var parentNode = doc.GetElementbyId("add_manga_status"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Status = (MangaCompletionStatus)childNode.GetAttributeValue("value", -1); + break; + } + } + + // Enable rereading + results.EnableRereading = doc.GetElementbyId("add_manga_is_rereading").Attributes["checked"] == null ? 0 : 1; + + // Score + parentNode = doc.GetElementbyId("add_manga_score"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Score = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Start date + int day = -1; + int month = -1; + int year = -1; + parentNode = doc.GetElementbyId("add_manga_start_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_start_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_start_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateStart = null; + } + else + { + results.DateStart = new DateTime(year, month, day); + } + + // Date finish + parentNode = doc.GetElementbyId("add_manga_finish_date_month"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + month = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_finish_date_day"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + day = childNode.GetAttributeValue("value", -1); + break; + } + } + parentNode = doc.GetElementbyId("add_manga_finish_date_year"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + year = childNode.GetAttributeValue("value", -1); + break; + } + } + if (month == -1 || day == -1 || year == -1) + { + results.DateFinish = null; + } + else + { + results.DateFinish = new DateTime(year, month, day); + } + + // Tags + results.Tags = doc.GetElementbyId("add_manga_tags").InnerText; + + // Priority + parentNode = doc.GetElementbyId("add_manga_priority"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.Priority = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Times reread + results.TimesReread = doc.GetElementbyId("add_manga_num_read_times").GetAttributeValue("value", -1); + + // Reread value + parentNode = doc.GetElementbyId("add_manga_reread_value"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + results.RereadValue = childNode.GetAttributeValue("value", -1); + break; + } + } + + // Comments + results.Comments = doc.GetElementbyId("add_manga_comments").InnerText; + + // Enable discussion + parentNode = doc.GetElementbyId("add_manga_is_asked_to_discuss"); + foreach (var childNode in parentNode.ChildNodes) + { + if (childNode.Attributes["selected"] != null) + { + // Because 'Enable discussion = 1' sent for update sets the first options of the dropdown, which corresponds to 0 and vice versa... + int temp = childNode.GetAttributeValue("value", -1); + temp = temp == 1 ? 0 : 1; + results.EnableDiscussion = temp; + break; + } + } + + return results; + } + } +} diff --git a/MalApi.UnitTests/MyAnimeListApiTests.cs b/MalApi.UnitTests/MyAnimeListApiTests.cs index 12ae0f0..768e6b6 100644 --- a/MalApi.UnitTests/MyAnimeListApiTests.cs +++ b/MalApi.UnitTests/MyAnimeListApiTests.cs @@ -64,7 +64,7 @@ public void TestScrapeUserAnimeDetailsFromHtml() using (MyAnimeListApi api = new MyAnimeListApi()) { - AnimeUpdate results = api.ScrapeUserAnimeDetailsFromHtml(html); + AnimeUpdate results = MalDetailScrapingUtils.ScrapeUserAnimeDetailsFromHtml(html); Assert.Equal(info.Episode, results.Episode); Assert.Equal(info.Status, results.Status); @@ -112,7 +112,7 @@ public void TestScrapeUserMangaDetailsFromHtml() using (MyAnimeListApi api = new MyAnimeListApi()) { - MangaUpdate results = api.ScrapeUserMangaDetailsFromHtml(html); + MangaUpdate results = MalDetailScrapingUtils.ScrapeUserMangaDetailsFromHtml(html); Assert.Equal(info.Chapter, results.Chapter); Assert.Equal(info.Volume, results.Volume); diff --git a/MalApi/MalApi.csproj b/MalApi/MalApi.csproj index f5db073..072534c 100644 --- a/MalApi/MalApi.csproj +++ b/MalApi/MalApi.csproj @@ -41,7 +41,6 @@ - diff --git a/MalApi/MyAnimeListApi.cs b/MalApi/MyAnimeListApi.cs index 6833a4e..f46aefc 100644 --- a/MalApi/MyAnimeListApi.cs +++ b/MalApi/MyAnimeListApi.cs @@ -8,7 +8,6 @@ using System.Net.Http.Headers; using System.Threading.Tasks; using System.Threading; -using HtmlAgilityPack; namespace MalApi { @@ -17,11 +16,6 @@ namespace MalApi /// public class MyAnimeListApi : IMyAnimeListApi { - private static readonly string NoRedirectMalUri = "https://myanimelist.net/pressroom"; - private static readonly string LoginUri = "https://myanimelist.net/login.php"; - private static readonly string UserAnimeDetailsUri = "https://myanimelist.net/editlist.php?type=anime&id={0}"; - private static readonly string UserMangaDetailsUri = "https://myanimelist.net/panel.php?go=editmanga&id={0}"; - private static readonly string AnimeDetailsUrlFormat = "https://myanimelist.net/anime/{0}"; private const string RecentOnlineUsersUri = "https://myanimelist.net/users.php"; @@ -53,8 +47,6 @@ public int TimeoutInMs private HttpClientHandler m_httpHandler; private HttpClient m_httpClient; - private string CsrfToken { get; set; } - public MyAnimeListApi() { m_httpHandler = new HttpClientHandler() @@ -563,7 +555,6 @@ private RecentUsersResults ScrapeUsersFromHtml(string recentUsersHtml) return new RecentUsersResults(users); } - private static Lazy s_animeDetailsRegex = new Lazy(() => new Regex( @"Genres:\s*?(?:\d+)/[^""]+?""[^>]*?>(?.*?)(?:, )?)*", RegexOptions.Compiled)); @@ -581,16 +572,6 @@ public Task GetAnimeDetailsAsync(int animeId) return GetAnimeDetailsAsync(animeId, CancellationToken.None); } - public Task GetUserAnimeDetailsAsync(string username, string password, int animeId) - { - return GetUserAnimeDetailsAsync(username, password, animeId, CancellationToken.None); - } - - public Task GetUserMangaDetailsAsync(string username, string password, int mangaId) - { - return GetUserMangaDetailsAsync(username, password, mangaId, CancellationToken.None); - } - /// /// Gets information from an anime's "details" page. This method uses HTML scraping and so may break if MAL changes the HTML. /// This method does not require a MAL API key. @@ -623,116 +604,6 @@ public async Task GetAnimeDetailsAsync(int animeId, Cancell } } - public async Task GetUserAnimeDetailsAsync(string username, string password, int animeId, CancellationToken cancellationToken) - { - string url = NoRedirectMalUri; - - HttpRequestMessage request = InitNewRequest(url, HttpMethod.Get); - - Logging.Log.InfoFormat("Getting user anime details for anime ID {0} from {1}.", animeId, url); - - try - { - // Get CSRF token - await ProcessRequestAsync(request, ParseCsrfTokenFromHtml, - cancellationToken: cancellationToken, - baseErrorMessage: "Failed connecting to MAL") - .ConfigureAwait(continueOnCapturedContext: false); - - // Login through the web form - url = LoginUri; - request = InitNewRequest(url, HttpMethod.Post); - - var contentPairs = new List> - { - new KeyValuePair("user_name", username), - new KeyValuePair("password", password), - new KeyValuePair("cookie", "1"), - new KeyValuePair("sublogin", "Login"), - new KeyValuePair("submit", "1"), - new KeyValuePair("csrf_token", CsrfToken) - }; - var content = new FormUrlEncodedContent(contentPairs); - request.Content = content; - - await ProcessRequestAsync(request, WebFormLoginHandler, - cancellationToken: cancellationToken, - baseErrorMessage: string.Format("Failed to log in for user {0}.", username)) - .ConfigureAwait(continueOnCapturedContext: false); - - // Retrieve anime specific info for user - url = string.Format(UserAnimeDetailsUri, animeId); - request = InitNewRequest(url, HttpMethod.Get); - - AnimeUpdate results = await ProcessRequestAsync(request, ScrapeUserAnimeDetailsFromHtml, - cancellationToken: cancellationToken, - baseErrorMessage: string.Format("Failed getting user anime details for user {0} anime ID {1}.", username, animeId)) - .ConfigureAwait(continueOnCapturedContext: false); - Logging.Log.InfoFormat("Successfully got details from {0}.", url); - return results; - } - catch (OperationCanceledException) - { - Logging.Log.InfoFormat("Canceled getting anime details for anime ID {0}.", animeId); - throw; - } - } - - public async Task GetUserMangaDetailsAsync(string username, string password, int mangaId, CancellationToken cancellationToken) - { - string url = NoRedirectMalUri; - - HttpRequestMessage request = InitNewRequest(url, HttpMethod.Get); - - Logging.Log.InfoFormat("Getting user manga details for manga ID {0} from {1}.", mangaId, url); - - try - { - // Get CSRF token - await ProcessRequestAsync(request, ParseCsrfTokenFromHtml, - cancellationToken: cancellationToken, - baseErrorMessage: "Failed connecting to MAL") - .ConfigureAwait(continueOnCapturedContext: false); - - // Login through the web form - url = LoginUri; - request = InitNewRequest(url, HttpMethod.Post); - - var contentPairs = new List> - { - new KeyValuePair("user_name", username), - new KeyValuePair("password", password), - new KeyValuePair("cookie", "1"), - new KeyValuePair("sublogin", "Login"), - new KeyValuePair("submit", "1"), - new KeyValuePair("csrf_token", CsrfToken) - }; - var content = new FormUrlEncodedContent(contentPairs); - request.Content = content; - - await ProcessRequestAsync(request, WebFormLoginHandler, - cancellationToken: cancellationToken, - baseErrorMessage: string.Format("Failed to log in for user {0}.", username)) - .ConfigureAwait(continueOnCapturedContext: false); - - // Retrieve anime specific info for user - url = string.Format(UserMangaDetailsUri, mangaId); - request = InitNewRequest(url, HttpMethod.Get); - - MangaUpdate results = await ProcessRequestAsync(request, ScrapeUserMangaDetailsFromHtml, - cancellationToken: cancellationToken, - baseErrorMessage: string.Format("Failed getting user manga details for user {0} manga ID {1}.", username, mangaId)) - .ConfigureAwait(continueOnCapturedContext: false); - Logging.Log.InfoFormat("Successfully got details from {0}.", url); - return results; - } - catch (OperationCanceledException) - { - Logging.Log.InfoFormat("Canceled getting anime details for anime ID {0}.", mangaId); - throw; - } - } - /// /// Gets information from an anime's "details" page. This method uses HTML scraping and so may break if MAL changes the HTML. /// This method does not require a MAL API key. @@ -745,16 +616,6 @@ public AnimeDetailsResults GetAnimeDetails(int animeId) return GetAnimeDetailsAsync(animeId).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); } - public AnimeUpdate GetUserAnimeDetails(string username, string password, int animeId) - { - return GetUserAnimeDetailsAsync(username, password, animeId).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); - } - - public MangaUpdate GetUserMangaDetails(string username, string password, int mangaId) - { - return GetUserMangaDetailsAsync(username, password, mangaId).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); - } - // If getting anime details page returned a 404, throw a MalAnimeNotFound exception instead of letting // a generic MalApiException be thrown. private static AnimeDetailsResults GetAnimeDetailsHttpErrorStatusHandler(HttpResponseMessage response, int animeId, out bool handled) @@ -794,368 +655,6 @@ internal AnimeDetailsResults ScrapeAnimeDetailsFromHtml(string animeDetailsHtml, return new AnimeDetailsResults(genres); } - // internal for unit testing - public string ParseCsrfTokenFromHtml(string html) - { - Match match = Regex.Match(html, @""); - if (match.Success) - { - CsrfToken = match.Groups[1].ToString(); - } - - return CsrfToken; - } - - // internal for unit testing - public string WebFormLoginHandler(string responseBody) - { - if (responseBody.Contains("Your username or password is incorrect.")) - { - throw new MalApiRequestException("Failed to log in. Recheck credentials."); - } - - return null; - } - - // internal for unit testing - internal AnimeUpdate ScrapeUserAnimeDetailsFromHtml(string userAnimeDetailsHtml) - { - AnimeUpdate results = new AnimeUpdate(); - - var doc = new HtmlDocument(); - doc.LoadHtml(userAnimeDetailsHtml); - - // Episode - results.Episode = doc.GetElementbyId("add_anime_num_watched_episodes").GetAttributeValue("value", -1); - - // Status - var parentNode = doc.GetElementbyId("add_anime_status"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - results.Status = (AnimeCompletionStatus)childNode.GetAttributeValue("value", -1); - break; - } - } - - // Enable rewatching - results.EnableRewatching = doc.GetElementbyId("add_anime_is_rewatching").Attributes["checked"] == null ? 0 : 1; - - // Score - parentNode = doc.GetElementbyId("add_anime_score"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - results.Score = childNode.GetAttributeValue("value", -1); - break; - } - } - - // Start date - int day = -1; - int month = -1; - int year = -1; - parentNode = doc.GetElementbyId("add_anime_start_date_month"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - month = childNode.GetAttributeValue("value", -1); - break; - } - } - parentNode = doc.GetElementbyId("add_anime_start_date_day"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - day = childNode.GetAttributeValue("value", -1); - break; - } - } - parentNode = doc.GetElementbyId("add_anime_start_date_year"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - year = childNode.GetAttributeValue("value", -1); - break; - } - } - if (month == -1 || day == -1 || year == -1) - { - results.DateStart = null; - } - else - { - results.DateStart = new DateTime(year, month, day); - } - - // Date finish - parentNode = doc.GetElementbyId("add_anime_finish_date_month"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - month = childNode.GetAttributeValue("value", -1); - break; - } - } - parentNode = doc.GetElementbyId("add_anime_finish_date_day"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - day = childNode.GetAttributeValue("value", -1); - break; - } - } - parentNode = doc.GetElementbyId("add_anime_finish_date_year"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - year = childNode.GetAttributeValue("value", -1); - break; - } - } - if (month == -1 || day == -1 || year == -1) - { - results.DateFinish = null; - } - else - { - results.DateFinish = new DateTime(year, month, day); - } - - // Tags - results.Tags = doc.GetElementbyId("add_anime_tags").InnerText; - - // Priority - parentNode = doc.GetElementbyId("add_anime_priority"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - results.Priority = childNode.GetAttributeValue("value", -1); - break; - } - } - - // Storage type - parentNode = doc.GetElementbyId("add_anime_storage_type"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - results.StorageType = childNode.GetAttributeValue("value", -1); - break; - } - } - - // Storage value - results.StorageValue = doc.GetElementbyId("add_anime_storage_value").GetAttributeValue("value", -1); - - // Times rewatched - results.TimesRewatched = doc.GetElementbyId("add_anime_num_watched_times").GetAttributeValue("value", -1); - - // Rewatch value - parentNode = doc.GetElementbyId("add_anime_rewatch_value"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - results.RewatchValue = childNode.GetAttributeValue("value", -1); - break; - } - } - - // Comments - results.Comments = doc.GetElementbyId("add_anime_comments").InnerText; - - // Enable discussion - parentNode = doc.GetElementbyId("add_anime_is_asked_to_discuss"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - // Because 'Enable discussion = 1' sent for update sets the first options of the dropdown, which corresponds to 0 and vice versa... - int temp = childNode.GetAttributeValue("value", -1); - temp = temp == 1 ? 0 : 1; - results.EnableDiscussion = temp; - break; - } - } - - return results; - } - - // internal for unit testing - internal MangaUpdate ScrapeUserMangaDetailsFromHtml(string userMangaDetailsHtml) - { - MangaUpdate results = new MangaUpdate(); - - var doc = new HtmlDocument(); - doc.LoadHtml(userMangaDetailsHtml); - - // Chapter - results.Chapter = doc.GetElementbyId("add_manga_num_read_chapters").GetAttributeValue("value", -1); - - // Volume - results.Volume = doc.GetElementbyId("add_manga_num_read_volumes").GetAttributeValue("value", -1); - - // Status - var parentNode = doc.GetElementbyId("add_manga_status"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - results.Status = (MangaCompletionStatus)childNode.GetAttributeValue("value", -1); - break; - } - } - - // Enable rereading - results.EnableRereading = doc.GetElementbyId("add_manga_is_rereading").Attributes["checked"] == null ? 0 : 1; - - // Score - parentNode = doc.GetElementbyId("add_manga_score"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - results.Score = childNode.GetAttributeValue("value", -1); - break; - } - } - - // Start date - int day = -1; - int month = -1; - int year = -1; - parentNode = doc.GetElementbyId("add_manga_start_date_month"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - month = childNode.GetAttributeValue("value", -1); - break; - } - } - parentNode = doc.GetElementbyId("add_manga_start_date_day"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - day = childNode.GetAttributeValue("value", -1); - break; - } - } - parentNode = doc.GetElementbyId("add_manga_start_date_year"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - year = childNode.GetAttributeValue("value", -1); - break; - } - } - if (month == -1 || day == -1 || year == -1) - { - results.DateStart = null; - } - else - { - results.DateStart = new DateTime(year, month, day); - } - - // Date finish - parentNode = doc.GetElementbyId("add_manga_finish_date_month"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - month = childNode.GetAttributeValue("value", -1); - break; - } - } - parentNode = doc.GetElementbyId("add_manga_finish_date_day"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - day = childNode.GetAttributeValue("value", -1); - break; - } - } - parentNode = doc.GetElementbyId("add_manga_finish_date_year"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - year = childNode.GetAttributeValue("value", -1); - break; - } - } - if (month == -1 || day == -1 || year == -1) - { - results.DateFinish = null; - } - else - { - results.DateFinish = new DateTime(year, month, day); - } - - // Tags - results.Tags = doc.GetElementbyId("add_manga_tags").InnerText; - - // Priority - parentNode = doc.GetElementbyId("add_manga_priority"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - results.Priority = childNode.GetAttributeValue("value", -1); - break; - } - } - - // Times reread - results.TimesReread = doc.GetElementbyId("add_manga_num_read_times").GetAttributeValue("value", -1); - - // Reread value - parentNode = doc.GetElementbyId("add_manga_reread_value"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - results.RereadValue = childNode.GetAttributeValue("value", -1); - break; - } - } - - // Comments - results.Comments = doc.GetElementbyId("add_manga_comments").InnerText; - - // Enable discussion - parentNode = doc.GetElementbyId("add_manga_is_asked_to_discuss"); - foreach (var childNode in parentNode.ChildNodes) - { - if (childNode.Attributes["selected"] != null) - { - // Because 'Enable discussion = 1' sent for update sets the first options of the dropdown, which corresponds to 0 and vice versa... - int temp = childNode.GetAttributeValue("value", -1); - temp = temp == 1 ? 0 : 1; - results.EnableDiscussion = temp; - break; - } - } - - return results; - } - public void Dispose() { m_httpClient.Dispose();