def test_generating_anime_media_list_entry(self): """ Tests generating an anime media list entry object :return: None """ data = self.generate_sample_anime_entry() self.assertEqual(data.id, Id({IdType.MYANIMELIST: 1})) self.assertEqual(data.title, Title({TitleType.ROMAJI: "Test"})) self.assertEqual(data.relations, [ Relation(Id({IdType.MYANIMELIST: 1}), MediaType.ANIME, Id({IdType.MYANIMELIST: 2}), MediaType.MANGA, RelationType.SEQUEL) ]) self.assertEqual(data.releasing_status, ReleasingStatus.FINISHED) self.assertEqual(data.releasing_start, Date(2018, 1, 1)) self.assertEqual(data.releasing_end, Date(2018, 4, 4)) self.assertEqual(data.episode_count, 12) self.assertEqual(data.episode_duration, 25) self.assertEqual(data.cover_url, "https://example.com/image.png") self.assertEqual(data.username, "namboy94") self.assertEqual(data.score, Score(55, ScoreType.PERCENTAGE)) self.assertEqual(data.consuming_status, ConsumingStatus.COMPLETED) self.assertEqual(data.episode_progress, 12) self.assertEqual(data.consuming_start, Date(2018, 1, 1)) self.assertEqual(data.consuming_end, Date(2018, 4, 4)) self.assertEqual(data.media_type, MediaType.ANIME)
def test_retrieving_non_existant_list_entry(self): """ Tests retrieving entries that are not in a user's list Uses very badly rated entries to make sure that they never get added to the list, breaking the test :return: None """ for media_type, _id in { MediaType.ANIME: Id({ IdType.KITSU: 378, # Mars of Destruction IdType.MYANIMELIST: 413, IdType.ANILIST: 413 }), MediaType.MANGA: Id({ IdType.KITSU: 45257, # Treasure Hunter Kukai IdType.MYANIMELIST: 539, IdType.ANILIST: 75257 }), }.items(): self.assertIsNone(self.api.get_list_entry( media_type, _id, self.username )) self.assertIsNone(self.api.get_user_data( media_type, _id, self.username ))
def test_equality(self): """ Tests that the equality of the objects is handled correctly :return: None """ id_one = Id({IdType.MYANIMELIST: 1}) id_two = Id({IdType.MYANIMELIST: 2}) id_three = Id({IdType.MYANIMELIST: 3}) one = Relation(id_one, MediaType.ANIME, id_two, MediaType.ANIME, RelationType.SEQUEL) two = Relation(id_one, MediaType.ANIME, id_two, MediaType.ANIME, RelationType.SEQUEL) three = Relation(id_one, MediaType.ANIME, id_three, MediaType.ANIME, RelationType.SEQUEL) four = Relation(id_one, MediaType.ANIME, id_two, MediaType.ANIME, RelationType.ADAPTATION) five = Relation(id_one, MediaType.ANIME, id_two, MediaType.MANGA, RelationType.SEQUEL) self.assertNotEqual(one, "Test") self.assertEqual(one, two) self.assertNotEqual(two, three) self.assertNotEqual(two, four) self.assertNotEqual(three, four) self.assertNotEqual(one, five)
def test_invalid_constructor_parameters(self): """ Tests using invalid parameter types with the constructor :return: None """ source = Id({IdType.MYANIMELIST: 1}) dest = Id({IdType.MYANIMELIST: 2}) for parameters in [ (None, MediaType.ANIME, dest, MediaType.ANIME, RelationType.SEQUEL), (source, MediaType.ANIME, None, MediaType.ANIME, RelationType.SEQUEL), (source, MediaType.ANIME, dest, MediaType.ANIME, None), (1, MediaType.ANIME, 2, MediaType.ANIME, RelationType.SEQUEL), (True, MediaType.ANIME, False, MediaType.ANIME, RelationType.SEQUEL), (source, MediaType.ANIME, dest, MediaType.ANIME, "SEQUEL"), (source, "ANIME", dest, MediaType.ANIME, RelationType.SEQUEL), (source, MediaType.ANIME, dest, "MANGA", RelationType.SEQUEL) ]: try: Relation(*parameters) self.fail() except TypeError: pass
def test_string_representation(self): """ Tests that the string representation is correct :return: None """ source = Id({IdType.MYANIMELIST: 1}) dest = Id({IdType.MYANIMELIST: 2}) relation = Relation(source, MediaType.ANIME, dest, MediaType.ANIME, RelationType.SEQUEL) representation = str(relation) serialised = json.loads(representation) self.assertEqual(relation, Relation.deserialize(serialised))
def generate_sample_manga_data() -> MangaData: """ Generates a generic MangaData object :return: The generated manga data object """ return MangaData(Id( {IdType.MYANIMELIST: 1}), Title({TitleType.ROMAJI: "Test"}), [ Relation(Id({IdType.MYANIMELIST: 1}), MediaType.MANGA, Id({IdType.MYANIMELIST: 2}), MediaType.MANGA, RelationType.SEQUEL) ], ReleasingStatus.FINISHED, Date(2018, 1, 1), Date(2018, 4, 4), "https://example.com/image.png", 100, 10)
def test_equality(self): """ Tests that the equality of the objects is handled correctly :return: None """ one = Id({IdType.MYANIMELIST: 1, IdType.ANILIST: 2}) two = Id({IdType.MYANIMELIST: 1, IdType.ANILIST: 2}) three = Id({IdType.MYANIMELIST: 1}) self.assertEqual(one, two) self.assertNotEqual(two, three) self.assertNotEqual(one, "Test")
def test_caching_anime(self): """ Tests that the caching works correctly for media data :return: None """ self.api.cache = Cache(self.cache.cache_location) for media_type, english, _id in [ (MediaType.ANIME, "Steins;Gate", Id({ IdType.KITSU: 5646, IdType.MYANIMELIST: 9253, IdType.ANILIST: 9253 })), (MediaType.MANGA, "Spice & Wolf", Id({ IdType.MYANIMELIST: 9115, IdType.KITSU: 18471, IdType.ANILIST: 39115 })) ]: fetched_entry = self.api.get_list_entry( media_type, _id, self.username ) fetched_data = self.api.get_data(media_type, _id) cached_entry = self.api.cache.get_media_list_entry( self.api.id_type, media_type, _id, self.username ) cached_data = self.api.cache.get_media_data( self.api.id_type, media_type, _id ) self.assertEqual( fetched_data.title.get(TitleType.ENGLISH), english ) self.assertEqual( fetched_entry.title.get(TitleType.ENGLISH), english ) self.assertEqual(fetched_data, cached_data) self.assertEqual(fetched_entry, cached_entry) def raise_value_error(): raise ValueError() # Makes sure that cached value is used from now on with mock.patch("requests.post", new=raise_value_error): with mock.patch("requests.get", new=raise_value_error): new_fetched_data = self.api.get_data(media_type, _id) new_fetched_entry = self.api.get_list_entry( media_type, _id, self.username ) self.assertEqual(new_fetched_data, cached_data) self.assertEqual(new_fetched_entry, cached_entry)
def test_invalid_deserialization(self): """ Tests that invalid serialized data raises ValueErrors when deserialized :return: None """ def attempt_deserialize(media_cls: type(MediaType), data: dict): try: media_cls.deserialize(data) self.fail() except (ValueError, TypeError): pass for media_class, sample in [ (AnimeData, self.generate_sample_serialized_anime_data()), (MangaData, self.generate_sample_serialized_manga_data()) ]: for key, value in sample.items(): for faux_value in [2000, "Hello", Id({IdType.KITSU: 1})]: if type(faux_value) != type(value): copy = deepcopy(sample) copy[key] = faux_value attempt_deserialize(media_class, copy) copy = deepcopy(sample) copy.pop(key) attempt_deserialize(media_class, copy)
def test_loading_and_retrieving_cache(self): """ Tests writing some data into the cache and then reloading it in a different Cache object :return: None """ entry = TestMediaListEntry.generate_sample_anime_entry() one = entry.id two = Id({IdType.MYANIMELIST: 2}) user = entry.username self.cache.add(IdType.MYANIMELIST, entry.get_media_data()) self.cache.add(IdType.MYANIMELIST, entry.get_user_data()) entry.id = two self.cache.add(IdType.MYANIMELIST, entry) self.cache.write() new_cache = Cache("testdir/.cache") for cache in [self.cache, new_cache]: for _id in [one, two]: entry.id = _id self.assertEqual( cache.get_media_data(IdType.MYANIMELIST, MediaType.ANIME, _id), entry.get_media_data()) self.assertEqual( cache.get_media_user_data(IdType.MYANIMELIST, MediaType.ANIME, _id, user), entry.get_user_data()) self.assertEqual( cache.get_media_list_entry(IdType.MYANIMELIST, MediaType.ANIME, _id, user), entry)
def test_equality(self): """ Tests that the equality of the objects is handled correctly :return: None """ one = self.generate_sample_anime_entry() two = self.generate_sample_anime_entry() self.assertEqual(one, two) two.id = Id({IdType.KITSU: 1}) self.assertNotEqual(one, two) two = self.generate_sample_anime_entry() two.releasing_start = None self.assertNotEqual(one, two) two = self.generate_sample_anime_entry() two.username = "******" self.assertNotEqual(one, two) two = self.generate_sample_anime_entry() two.consuming_end = None self.assertNotEqual(one, two) self.assertNotEqual(one, self.generate_sample_manga_entry())
def test_string_representation(self): """ Tests that the string representation is correct :return: None """ _id = Id({IdType.MYANIMELIST: 1, IdType.ANILIST: 2}) representation = str(_id) serialised = json.loads(representation) self.assertEqual(_id, Id.deserialize(serialised))
def generate_sample_manga_user_data() -> MangaUserData: """ Generates a sample MangaUserData object :return: The generated MangaUserData object """ return MangaUserData(Id({IdType.MYANIMELIST: 1}), "namboy94", Score(55, ScoreType.PERCENTAGE), ConsumingStatus.COMPLETED, Date(2018, 1, 1), Date(2018, 4, 4), 100, 10)
def __generate_id_obj(self, _id: int or Id) -> Id: """ Generates an Id object if the given ID is an integer :param _id: The ID to make sure is an Id object :return: The generated Id object """ if isinstance(_id, int): _id = Id({self.id_type: _id}) return _id
def test_serialization(self): """ Tests serializing an ID object :return: None """ ob = Id({IdType.MYANIMELIST: 1, IdType.ANILIST: 2}) data = ob.serialize() self.assertEqual(data, {"MYANIMELIST": 1, "ANILIST": 2, "KITSU": None})
def test_deserialization(self): """ Tests deserializing an ID object :return: None """ source = Id({IdType.MYANIMELIST: 1}) dest = Id({IdType.MYANIMELIST: 2}) data = { "source": source.serialize(), "source_type": "ANIME", "dest": dest.serialize(), "dest_type": "MANGA", "type": "SEQUEL" } self.assertEqual( Relation.deserialize(data), Relation(source, MediaType.ANIME, dest, MediaType.MANGA, RelationType.SEQUEL))
def test_serialization(self): """ Tests serializing a Relation object :return: None """ source = Id({IdType.MYANIMELIST: 1}) dest = Id({IdType.MYANIMELIST: 2}) ob = Relation(source, MediaType.ANIME, dest, MediaType.MANGA, RelationType.SEQUEL) data = ob.serialize() self.assertEqual( data, { "source": source.serialize(), "source_type": "ANIME", "dest": dest.serialize(), "dest_type": "MANGA", "type": "SEQUEL" })
def test_fetching_different_id_types(self): """ Tests generating an ID using the constructor and fetching the different IDs :return: None """ _id = Id({IdType.MYANIMELIST: 1, IdType.ANILIST: 2, IdType.KITSU: 3}) self.assertEqual(1, _id.get(IdType.MYANIMELIST)) self.assertEqual(2, _id.get(IdType.ANILIST)) self.assertEqual(3, _id.get(IdType.KITSU))
def test_unfilled_entries(self): """ Tests that unfilled ID entries lead to Null values for the respective IDs :return: None """ _id = Id({IdType.MYANIMELIST: 1}) self.assertEqual(1, _id.get(IdType.MYANIMELIST)) self.assertEqual(None, _id.get(IdType.ANILIST)) self.assertEqual(None, _id.get(IdType.KITSU))
def test_retrieving_data(self): """ Tests retrieving a data, user data and list entries for both anime and manga :return: None """ for media_type, english, _id in [ (MediaType.ANIME, "Steins;Gate", Id({ IdType.KITSU: 5646, IdType.MYANIMELIST: 9253, IdType.ANILIST: 9253 })), (MediaType.MANGA, "Spice & Wolf", Id({ IdType.MYANIMELIST: 9115, IdType.KITSU: 18471, IdType.ANILIST: 39115 })) ]: media_data = self.api.get_data(media_type, _id) user_data = self.api.get_user_data(media_type, _id, self.username) entry = self.api.get_list_entry(media_type, _id, self.username) self.assertEqual( media_data.id.get(self.api.id_type), _id.get(self.api.id_type) ) self.assertEqual( user_data.id.get(self.api.id_type), _id.get(self.api.id_type) ) self.assertEqual( entry.id.get(self.api.id_type), _id.get(self.api.id_type) ) self.assertEqual(media_data.title.get(TitleType.ENGLISH), english) self.assertEqual(entry.title.get(TitleType.ENGLISH), english) self.assertEqual(media_data, entry.get_media_data()) self.assertEqual(user_data, entry.get_user_data())
def test_generating_manga_data(self): """ Tests generating a manga data object :return: None """ data = self.generate_sample_manga_data() self.assertEqual(data.id, Id({IdType.MYANIMELIST: 1})) self.assertEqual(data.title, Title({TitleType.ROMAJI: "Test"})) self.assertEqual(data.relations, [ Relation(Id({IdType.MYANIMELIST: 1}), MediaType.MANGA, Id({IdType.MYANIMELIST: 2}), MediaType.MANGA, RelationType.SEQUEL) ]) self.assertEqual(data.releasing_status, ReleasingStatus.FINISHED) self.assertEqual(data.releasing_start, Date(2018, 1, 1)) self.assertEqual(data.releasing_end, Date(2018, 4, 4)) self.assertEqual(data.chapter_count, 100) self.assertEqual(data.volume_count, 10) self.assertEqual(data.cover_url, "https://example.com/image.png") self.assertEqual(data.media_type, MediaType.MANGA)
def test_no_entries(self): """ Tests that the constructor raises a ValueError when no ID at all is provided :return: None """ try: Id({}) self.fail() except ValueError: pass
def test_invalid_constructor_parameters(self): """ Tests using invalid parameter types with the constructor :return: None """ for parameters in [([], ), (100, )]: try: Id(*parameters) self.fail() except TypeError: pass
def test_deserialization(self): """ Tests deserializing an ID object :return: None """ self.assertEqual(Id.deserialize({ "MYANIMELIST": 1, "ANILIST": 2 }), Id({ IdType.MYANIMELIST: 1, IdType.ANILIST: 2 }))
def test_setting_ids(self): """ Tests manually setting IDs after construction :return: None """ _id = Id({IdType.MYANIMELIST: 1}) _id.set(100, IdType.MYANIMELIST) _id.set(200, IdType.ANILIST) _id.set(300, IdType.KITSU) self.assertEqual(100, _id.get(IdType.MYANIMELIST)) self.assertEqual(200, _id.get(IdType.ANILIST)) self.assertEqual(300, _id.get(IdType.KITSU))
def test_no_valid_entries(self): """ Tests that providing None values as the only IDs still result in a ValueError :return: None """ try: # noinspection PyTypeChecker Id({IdType.MYANIMELIST: None}) self.fail() except ValueError: pass
def test_setting_invalid_ids(self): """ Tests setting ids that are invalid types :return: None """ _id = Id({IdType.MYANIMELIST: 1}) for value in [None, "100", 100.0, True]: try: # noinspection PyTypeChecker _id.set(value, IdType.ANILIST) self.fail() except TypeError: pass
def test_getting_fresh_data(self): """ Tests retrieving fresh data :return: None """ self.api.cache.expiration = 6000 _id = Id({ IdType.KITSU: 5646, IdType.MYANIMELIST: 9253, IdType.ANILIST: 9253 }) media_data = self.api.get_anime_data(_id) user_data = self.api.get_anime_user_data(_id, self.username) original_media = deepcopy(media_data) original_user = deepcopy(user_data) self.assertEqual( self.api.cache.get_media_data( self.api.id_type, MediaType.ANIME, _id ), media_data ) self.assertEqual( self.api.cache.get_media_user_data( self.api.id_type, MediaType.ANIME, _id, self.username ), user_data ) media_data.title.set("Test", TitleType.ENGLISH) user_data.score = Score(0, ScoreType.PERCENTAGE) self.api.cache.add(self.api.id_type, media_data) self.api.cache.add(self.api.id_type, user_data) self.assertNotEqual(original_media, media_data) self.assertNotEqual(original_user, user_data) self.assertEqual(media_data, self.api.get_anime_data(_id)) self.assertEqual( user_data, self.api.get_anime_user_data(_id, self.username) ) fresh_media = self.api.get_anime_data(_id, True) fresh_user = self.api.get_anime_user_data(_id, self.username, True) self.assertNotEqual(fresh_media, media_data) self.assertEqual(fresh_media, original_media) self.assertNotEqual(fresh_user, user_data) self.assertEqual(fresh_user, original_user)
def generate_sample_serialized_anime_data() -> \ Dict[str, Optional[str or int or float or bool or Dict or List or Tuple or Set]]: """ Generates some sample serialized anime data :return: The serialized sample data """ return { "media_type": "ANIME", "id": Id({ IdType.MYANIMELIST: 1 }).serialize(), "title": Title({ TitleType.ROMAJI: "Test" }).serialize(), "relations": [ Relation(Id({IdType.MYANIMELIST: 1}), MediaType.ANIME, Id({IdType.MYANIMELIST: 2}), MediaType.MANGA, RelationType.SEQUEL).serialize() ], "releasing_status": ReleasingStatus.FINISHED.name, "releasing_start": Date(2018, 1, 1).serialize(), "releasing_end": Date(2018, 4, 4).serialize(), "episode_count": 12, "episode_duration": 25, "cover_url": "https://example.com/image.png" }
def test_important_relations(self): """ Tests if relations are correctly identified as "important" :return: None """ source = Id({IdType.MYANIMELIST: 1}) dest = Id({IdType.MYANIMELIST: 2}) for relation_type, important in { RelationType.SEQUEL: True, RelationType.PREQUEL: True, RelationType.PARENT: True, RelationType.SIDE_STORY: True, RelationType.SUMMARY: True, RelationType.SPIN_OFF: False, RelationType.CHARACTER: False, RelationType.ADAPTATION: False, RelationType.OTHER: False }.items(): same_type_relation = Relation(source, MediaType.ANIME, dest, MediaType.ANIME, relation_type) self.assertEqual(same_type_relation.is_important(), important) other_type_relation = Relation(source, MediaType.ANIME, dest, MediaType.MANGA, relation_type) self.assertFalse(other_type_relation.is_important())