Merge pull request #226 from pylast/more-tests

Add more tests and remove more dead Last.fm stuff
This commit is contained in:
Hugo 2017-10-19 23:53:10 +03:00 committed by GitHub
commit 5ae5f995cd
8 changed files with 276 additions and 197 deletions

View file

@ -97,9 +97,6 @@ IMAGES_ORDER_POPULARITY = "popularity"
IMAGES_ORDER_DATE = "dateadded" IMAGES_ORDER_DATE = "dateadded"
USER_MALE = 'Male'
USER_FEMALE = 'Female'
SCROBBLE_SOURCE_USER = "P" SCROBBLE_SOURCE_USER = "P"
SCROBBLE_SOURCE_NON_PERSONALIZED_BROADCAST = "R" SCROBBLE_SOURCE_NON_PERSONALIZED_BROADCAST = "R"
SCROBBLE_SOURCE_PERSONALIZED_BROADCAST = "E" SCROBBLE_SOURCE_PERSONALIZED_BROADCAST = "E"
@ -445,12 +442,6 @@ class _Network(object):
return ArtistSearch(artist_name, self) return ArtistSearch(artist_name, self)
def search_for_tag(self, tag_name):
"""Searches of a tag by its name. Returns a TagSearch object.
Use get_next_page() to retrieve sequences of results."""
return TagSearch(tag_name, self)
def search_for_track(self, artist_name, track_name): def search_for_track(self, artist_name, track_name):
"""Searches of a track by its name and its artist. Set artist to an """Searches of a track by its name and its artist. Set artist to an
empty string if not available. empty string if not available.
@ -1083,37 +1074,6 @@ class _BaseObject(object):
return seq return seq
def share(self, users, message=None):
"""
Shares this (sends out recommendations).
Parameters:
* users [User|str,]: A list that can contain usernames, emails,
User objects, or all of them.
* message str: A message to include in the recommendation message.
Only for Artist/Track.
"""
# Last.fm currently accepts a max of 10 recipient at a time
while len(users) > 10:
section = users[0:9]
users = users[9:]
self.share(section, message)
user_names = []
for user in users:
if isinstance(user, User):
user_names.append(user.get_name())
else:
user_names.append(user)
params = self._get_params()
recipients = ','.join(user_names)
params['recipient'] = recipients
if message:
params['message'] = message
self._request(self.ws_prefix + '.share', False, params)
def get_wiki_published_date(self): def get_wiki_published_date(self):
""" """
Returns the summary of the wiki. Returns the summary of the wiki.
@ -2092,11 +2052,6 @@ class Track(_Opus):
self._request(self.ws_prefix + '.unlove') self._request(self.ws_prefix + '.unlove')
def ban(self):
"""Ban this track from ever playing on the radio. """
self._request(self.ws_prefix + '.ban')
def get_similar(self): def get_similar(self):
""" """
Returns similar tracks for this track on the network, Returns similar tracks for this track on the network,
@ -2261,24 +2216,6 @@ class User(_BaseObject, _Chartable):
return seq return seq
def get_neighbours(self, limit=50, cacheable=True):
"""Returns a list of the user's friends."""
params = self._get_params()
if limit:
params['limit'] = limit
doc = self._request(
self.ws_prefix + '.getNeighbours', cacheable, params)
seq = []
names = _extract_all(doc, 'name')
for name in names:
seq.append(User(name, self.network))
return seq
def get_now_playing(self): def get_now_playing(self):
""" """
Returns the currently playing track, or None if nothing is playing. Returns the currently playing track, or None if nothing is playing.
@ -2356,20 +2293,6 @@ class User(_BaseObject, _Chartable):
return seq return seq
def get_id(self):
"""Returns the user ID."""
doc = self._request(self.ws_prefix + ".getInfo", True)
return _extract(doc, "id")
def get_language(self):
"""Returns the language code of the language used by the user."""
doc = self._request(self.ws_prefix + ".getInfo", True)
return _extract(doc, "lang")
def get_country(self): def get_country(self):
"""Returns the name of the country of the user.""" """Returns the name of the country of the user."""
@ -2382,27 +2305,6 @@ class User(_BaseObject, _Chartable):
else: else:
return Country(country, self.network) return Country(country, self.network)
def get_age(self):
"""Returns the user's age."""
doc = self._request(self.ws_prefix + ".getInfo", True)
return _number(_extract(doc, "age"))
def get_gender(self):
"""Returns the user's gender. Either USER_MALE or USER_FEMALE."""
doc = self._request(self.ws_prefix + ".getInfo", True)
value = _extract(doc, "gender")
if value == 'm':
return USER_MALE
elif value == 'f':
return USER_FEMALE
return None
def is_subscriber(self): def is_subscriber(self):
"""Returns whether the user is a subscriber or not. True or False.""" """Returns whether the user is a subscriber or not. True or False."""
@ -2551,39 +2453,6 @@ class User(_BaseObject, _Chartable):
return self._get_things( return self._get_things(
"getTopTracks", "track", Track, params, cacheable) "getTopTracks", "track", Track, params, cacheable)
def compare_with_user(self, user, shared_artists_limit=None):
"""
Compare this user with another Last.fm user.
Returns a sequence:
(tasteometer_score, (shared_artist1, shared_artist2, ...))
user: A User object or a username string/unicode object.
"""
if isinstance(user, User):
user = user.get_name()
params = self._get_params()
if shared_artists_limit:
params['limit'] = shared_artists_limit
params['type1'] = 'user'
params['type2'] = 'user'
params['value1'] = self.get_name()
params['value2'] = user
doc = self._request('tasteometer.compare', False, params)
score = _extract(doc, 'score')
artists = doc.getElementsByTagName('artists')[0]
shared_artists_names = _extract_all(artists, 'name')
shared_artists_seq = []
for name in shared_artists_names:
shared_artists_seq.append(Artist(name, self.network))
return (score, shared_artists_seq)
def get_image(self): def get_image(self):
"""Returns the user's avatar.""" """Returns the user's avatar."""
@ -2633,19 +2502,6 @@ class AuthenticatedUser(User):
self.name = _extract(doc, "name") self.name = _extract(doc, "name")
return self.name return self.name
def get_recommended_artists(self, limit=50, cacheable=False):
"""
Returns a sequence of Artist objects
if limit==None it will return all
"""
seq = []
for node in _collect_nodes(
limit, self, "user.getRecommendedArtists", cacheable):
seq.append(Artist(_extract(node, "name"), self.network))
return seq
class _Search(_BaseObject): class _Search(_BaseObject):
"""An abstract class. Use one of its derivatives.""" """An abstract class. Use one of its derivatives."""
@ -2729,27 +2585,6 @@ class ArtistSearch(_Search):
return seq return seq
class TagSearch(_Search):
"""Search for a tag by tag name."""
def __init__(self, tag_name, network):
_Search.__init__(self, "tag", {"tag": tag_name}, network)
def get_next_page(self):
"""Returns the next page of results as a sequence of Tag objects."""
master_node = self._retrieve_next_page()
seq = []
for node in master_node.getElementsByTagName("tag"):
tag = Tag(_extract(node, "name"), self.network)
tag.tag_count = _number(_extract(node, "count"))
seq.append(tag)
return seq
class TrackSearch(_Search): class TrackSearch(_Search):
""" """
Search for a track by track title. If you don't want to narrow the results Search for a track by track title. If you don't want to narrow the results

View file

@ -99,6 +99,17 @@ class TestPyLastAlbum(PyLastTestCase):
# Act / Assert # Act / Assert
self.assertTrue(album1 != album2) self.assertTrue(album1 != album2)
def test_get_cover_image(self):
# Arrange
album = self.network.get_album("Test Artist", "Test Album")
# Act
image = album.get_cover_image()
# Assert
self.assertTrue(image.startswith("https://"))
self.assertTrue(image.endswith(".png"))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(failfast=True) unittest.main(failfast=True)

View file

@ -11,6 +11,17 @@ from .test_pylast import PyLastTestCase
class TestPyLastArtist(PyLastTestCase): class TestPyLastArtist(PyLastTestCase):
def test_repr(self):
# Arrange
artist = pylast.Artist("Test Artist", self.network)
# Act
representation = repr(artist)
# Assert
self.assertTrue(
representation.startswith("pylast.Artist('Test Artist',"))
def test_artist_is_hashable(self): def test_artist_is_hashable(self):
# Arrange # Arrange
test_artist = self.network.get_artist("Test Artist") test_artist = self.network.get_artist("Test Artist")
@ -257,6 +268,17 @@ class TestPyLastArtist(PyLastTestCase):
# Assert # Assert
self.assertEqual(corrected_artist_name, "Guns N' Roses") self.assertEqual(corrected_artist_name, "Guns N' Roses")
def test_get_userplaycount(self):
# Arrange
artist = pylast.Artist("John Lennon", self.network,
username=self.username)
# Act
playcount = artist.get_userplaycount()
# Assert
self.assertGreaterEqual(playcount, 0)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(failfast=True) unittest.main(failfast=True)

View file

@ -11,6 +11,26 @@ from .test_pylast import PyLastTestCase
class TestPyLastLibrary(PyLastTestCase): class TestPyLastLibrary(PyLastTestCase):
def test_repr(self):
# Arrange
library = pylast.Library(user=self.username, network=self.network)
# Act
representation = repr(library)
# Assert
self.assertTrue(representation.startswith("pylast.Library("))
def test_str(self):
# Arrange
library = pylast.Library(user=self.username, network=self.network)
# Act
string = str(library)
# Assert
self.assertTrue(string.endswith("'s Library"))
def test_library_is_hashable(self): def test_library_is_hashable(self):
# Arrange # Arrange
library = pylast.Library(user=self.username, network=self.network) library = pylast.Library(user=self.username, network=self.network)
@ -25,6 +45,17 @@ class TestPyLastLibrary(PyLastTestCase):
# Act/Assert # Act/Assert
self.helper_validate_cacheable(library, "get_artists") self.helper_validate_cacheable(library, "get_artists")
def test_get_user(self):
# Arrange
library = pylast.Library(user=self.username, network=self.network)
user_to_get = self.network.get_user(self.username)
# Act
library_user = library.get_user()
# Assert
self.assertEqual(library_user, user_to_get)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(failfast=True) unittest.main(failfast=True)

View file

@ -30,6 +30,20 @@ class TestPyLastWithLibreFm(unittest.TestCase):
# Assert # Assert
self.assertEqual(name, "Radiohead") self.assertEqual(name, "Radiohead")
def test_repr(self):
# Arrange
secrets = load_secrets()
username = secrets["username"]
password_hash = secrets["password_hash"]
network = pylast.LibreFMNetwork(
password_hash=password_hash, username=username)
# Act
representation = repr(network)
# Assert
self.assertTrue(representation.startswith("pylast.LibreFMNetwork("))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(failfast=True) unittest.main(failfast=True)

View file

@ -302,6 +302,57 @@ class TestPyLastNetwork(PyLastTestCase):
self.assertEqual(msg, self.assertEqual(msg,
"Unauthorized Token - This token has not been issued") "Unauthorized Token - This token has not been issued")
def test_proxy(self):
# Arrange
host = "https://example.com"
port = 1234
# Act / Assert
self.network.enable_proxy(host, port)
self.assertTrue(self.network.is_proxy_enabled())
self.assertEqual(self.network._get_proxy(),
["https://example.com", 1234])
self.network.disable_proxy()
self.assertFalse(self.network.is_proxy_enabled())
def test_album_search(self):
# Arrange
album = "Nevermind"
# Act
search = self.network.search_for_album(album)
results = search.get_next_page()
# Assert
self.assertIsInstance(results, list)
self.assertIsInstance(results[0], pylast.Album)
def test_artist_search(self):
# Arrange
artist = "Nirvana"
# Act
search = self.network.search_for_artist(artist)
results = search.get_next_page()
# Assert
self.assertIsInstance(results, list)
self.assertIsInstance(results[0], pylast.Artist)
def test_track_search(self):
# Arrange
artist = "Nirvana"
track = "Smells Like Teen Spirit"
# Act
search = self.network.search_for_track(artist, track)
results = search.get_next_page()
# Assert
self.assertIsInstance(results, list)
self.assertIsInstance(results[0], pylast.Track)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(failfast=True) unittest.main(failfast=True)

View file

@ -104,6 +104,62 @@ class TestPyLastTrack(PyLastTestCase):
self.assertIsNotNone(wiki) self.assertIsNotNone(wiki)
self.assertGreaterEqual(len(wiki), 1) self.assertGreaterEqual(len(wiki), 1)
def test_track_get_duration(self):
# Arrange
track = pylast.Track("Nirvana", "Lithium", self.network)
# Act
duration = track.get_duration()
# Assert
self.assertGreaterEqual(duration, 200000)
def test_track_is_streamable(self):
# Arrange
track = pylast.Track("Nirvana", "Lithium", self.network)
# Act
streamable = track.is_streamable()
# Assert
self.assertFalse(streamable)
def test_track_is_fulltrack_available(self):
# Arrange
track = pylast.Track("Nirvana", "Lithium", self.network)
# Act
fulltrack_available = track.is_fulltrack_available()
# Assert
self.assertFalse(fulltrack_available)
def test_track_get_album(self):
# Arrange
track = pylast.Track("Nirvana", "Lithium", self.network)
# Act
album = track.get_album()
print(album)
# Assert
self.assertEqual(str(album), "Nirvana - Nevermind")
def test_track_get_similar(self):
# Arrange
track = pylast.Track("Cher", "Believe", self.network)
# Act
similar = track.get_similar()
# Assert
found = False
for track in similar:
if str(track.item) == "Madonna - Vogue":
found = True
break
self.assertTrue(found)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(failfast=True) unittest.main(failfast=True)

View file

@ -14,10 +14,59 @@ from .test_pylast import PyLastTestCase
class TestPyLastUser(PyLastTestCase): class TestPyLastUser(PyLastTestCase):
def test_repr(self):
# Arrange
user = self.network.get_user("RJ")
# Act
representation = repr(user)
# Assert
self.assertTrue(representation.startswith("pylast.User('RJ',"))
def test_str(self):
# Arrange
user = self.network.get_user("RJ")
# Act
string = str(user)
# Assert
self.assertEqual(string, "RJ")
def test_equality(self):
# Arrange
user_1a = self.network.get_user("RJ")
user_1b = self.network.get_user("RJ")
user_2 = self.network.get_user("Test User")
not_a_user = self.network
# Act / Assert
self.assertEqual(user_1a, user_1b)
self.assertTrue(user_1a == user_1b)
self.assertFalse(user_1a != user_1b)
self.assertNotEqual(user_1a, user_2)
self.assertTrue(user_1a != user_2)
self.assertFalse(user_1a == user_2)
self.assertNotEqual(user_1a, not_a_user)
self.assertTrue(user_1a != not_a_user)
self.assertFalse(user_1a == not_a_user)
def test_get_name(self):
# Arrange
user = self.network.get_user("RJ")
# Act
name = user.get_name(properly_capitalized=True)
# Assert
self.assertEqual(name, "RJ")
def test_get_user_registration(self): def test_get_user_registration(self):
# Arrange # Arrange
username = "RJ" user = self.network.get_user("RJ")
user = self.network.get_user(username)
# Act # Act
registered = user.get_registered() registered = user.get_registered()
@ -32,8 +81,7 @@ class TestPyLastUser(PyLastTestCase):
def test_get_user_unixtime_registration(self): def test_get_user_unixtime_registration(self):
# Arrange # Arrange
username = "RJ" user = self.network.get_user("RJ")
user = self.network.get_user(username)
# Act # Act
unixtime_registered = user.get_unixtime_registered() unixtime_registered = user.get_unixtime_registered()
@ -42,17 +90,6 @@ class TestPyLastUser(PyLastTestCase):
# Just check date because of timezones # Just check date because of timezones
self.assertEqual(unixtime_registered, u"1037793040") self.assertEqual(unixtime_registered, u"1037793040")
def test_get_genderless_user(self):
# Arrange
# Currently test_user has no gender set:
lastfm_user = self.network.get_user("test_user")
# Act
gender = lastfm_user.get_gender()
# Assert
self.assertIsNone(gender)
def test_get_countryless_user(self): def test_get_countryless_user(self):
# Arrange # Arrange
# Currently test_user has no country set: # Currently test_user has no country set:
@ -64,6 +101,16 @@ class TestPyLastUser(PyLastTestCase):
# Assert # Assert
self.assertIsNone(country) self.assertIsNone(country)
def test_user_get_country(self):
# Arrange
lastfm_user = self.network.get_user("RJ")
# Act
country = lastfm_user.get_country()
# Assert
self.assertEqual(str(country), "United Kingdom")
def test_user_equals_none(self): def test_user_equals_none(self):
# Arrange # Arrange
lastfm_user = self.network.get_user(self.username) lastfm_user = self.network.get_user(self.username)
@ -224,23 +271,6 @@ class TestPyLastUser(PyLastTestCase):
# Act/Assert # Act/Assert
self.helper_get_assert_charts(lastfm_user, dates[0]) self.helper_get_assert_charts(lastfm_user, dates[0])
# Commented out to avoid spamming
# def test_share_spam(self):
# # Arrange
# users_to_spam = [TODO_ENTER_SPAMEES_HERE]
# spam_message = "Dig the krazee sound!"
# artist = self.network.get_top_artists(limit=1)[0].item
# track = artist.get_top_tracks(limit=1)[0].item
# # Act
# artist.share(users_to_spam, spam_message)
# track.share(users_to_spam, spam_message)
# Assert
# Check inbox for spam!
# album/artist/track/user
def test_user_top_artists(self): def test_user_top_artists(self):
# Arrange # Arrange
lastfm_user = self.network.get_user(self.username) lastfm_user = self.network.get_user(self.username)
@ -443,6 +473,35 @@ class TestPyLastUser(PyLastTestCase):
# Assert # Assert
self.assertEqual(mbid, None) self.assertEqual(mbid, None)
def test_get_playcount(self):
# Arrange
user = self.network.get_user("RJ")
# Act
playcount = user.get_playcount()
# Assert
self.assertGreaterEqual(playcount, 128387)
def test_get_image(self):
# Arrange
user = self.network.get_user("RJ")
# Act / Assert
image = user.get_image()
self.assertTrue(image.startswith("https://"))
self.assertTrue(image.endswith(".png"))
def test_get_url(self):
# Arrange
user = self.network.get_user("RJ")
# Act / Assert
url = user.get_url()
self.assertEqual(url, "https://www.last.fm/user/rj")
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(failfast=True) unittest.main(failfast=True)