diff --git a/test/test_beatport.py b/test/test_beatport.py new file mode 100644 index 000000000..a1591d58c --- /dev/null +++ b/test/test_beatport.py @@ -0,0 +1,567 @@ +# -*- coding: utf-8 -*- +# This file is part of beets. +# Copyright 2016, Adrian Sampson. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +"""Tests for the 'beatport' plugin. +""" +from __future__ import division, absolute_import, print_function + +import unittest +from test import _common +from test.helper import TestHelper +import six +from datetime import timedelta + +from beetsplug import beatport +from beets import library + + +class BeatportTest(_common.TestCase, TestHelper): + def _make_release_response(self): + """Returns a dict that mimics a response from the beatport API. + + The results were retrived from: + https://oauth-api.beatport.com/catalog/3/releases?id=1742984 + The list of elements on the returned dict is incomplete, including just + those required for the tests on this class. + """ + results = { + "id": 1742984, + "type": "release", + "name": "Charade", + "slug": "charade", + "releaseDate": "2016-04-11", + "publishDate": "2016-04-11", + "audioFormat": "", + "category": "Release", + "currentStatus": "General Content", + "catalogNumber": "GR089", + "description": "", + "label": { + "id": 24539, + "name": "Gravitas Recordings", + "type": "label", + "slug": "gravitas-recordings" + }, + "artists": [{ + "id": 326158, + "name": "Supersillyus", + "slug": "supersillyus", + "type": "artist" + }], + "genres": [{ + "id": 9, + "name": "Breaks", + "slug": "breaks", + "type": "genre" + }], + } + return results + + def _make_tracks_response(self): + """Return a list that mimics a response from the beatport API. + + The results were retrived from: + https://oauth-api.beatport.com/catalog/3/tracks?releaseId=1742984 + The list of elements on the returned list is incomplete, including just + those required for the tests on this class. + """ + results = [{ + "id": 7817567, + "type": "track", + "sku": "track-7817567", + "name": "Mirage a Trois", + "trackNumber": 1, + "mixName": "Original Mix", + "title": "Mirage a Trois (Original Mix)", + "slug": "mirage-a-trois-original-mix", + "releaseDate": "2016-04-11", + "publishDate": "2016-04-11", + "currentStatus": "General Content", + "length": "7:05", + "lengthMs": 425421, + "bpm": 90, + "key": { + "standard": { + "letter": "G", + "sharp": False, + "flat": False, + "chord": "minor" + }, + "shortName": "Gmin" + }, + "artists": [{ + "id": 326158, + "name": "Supersillyus", + "slug": "supersillyus", + "type": "artist" + }], + "genres": [{ + "id": 9, + "name": "Breaks", + "slug": "breaks", + "type": "genre" + }], + "subGenres": [{ + "id": 209, + "name": "Glitch Hop", + "slug": "glitch-hop", + "type": "subgenre" + }], + "release": { + "id": 1742984, + "name": "Charade", + "type": "release", + "slug": "charade" + }, + "label": { + "id": 24539, + "name": "Gravitas Recordings", + "type": "label", + "slug": "gravitas-recordings", + "status": True + } + }, { + "id": 7817568, + "type": "track", + "sku": "track-7817568", + "name": "Aeon Bahamut", + "trackNumber": 2, + "mixName": "Original Mix", + "title": "Aeon Bahamut (Original Mix)", + "slug": "aeon-bahamut-original-mix", + "releaseDate": "2016-04-11", + "publishDate": "2016-04-11", + "currentStatus": "General Content", + "length": "7:38", + "lengthMs": 458000, + "bpm": 100, + "key": { + "standard": { + "letter": "G", + "sharp": False, + "flat": False, + "chord": "major" + }, + "shortName": "Gmaj" + }, + "artists": [{ + "id": 326158, + "name": "Supersillyus", + "slug": "supersillyus", + "type": "artist" + }], + "genres": [{ + "id": 9, + "name": "Breaks", + "slug": "breaks", + "type": "genre" + }], + "subGenres": [{ + "id": 209, + "name": "Glitch Hop", + "slug": "glitch-hop", + "type": "subgenre" + }], + "release": { + "id": 1742984, + "name": "Charade", + "type": "release", + "slug": "charade" + }, + "label": { + "id": 24539, + "name": "Gravitas Recordings", + "type": "label", + "slug": "gravitas-recordings", + "status": True + } + }, { + "id": 7817569, + "type": "track", + "sku": "track-7817569", + "name": "Trancendental Medication", + "trackNumber": 3, + "mixName": "Original Mix", + "title": "Trancendental Medication (Original Mix)", + "slug": "trancendental-medication-original-mix", + "releaseDate": "2016-04-11", + "publishDate": "2016-04-11", + "currentStatus": "General Content", + "length": "1:08", + "lengthMs": 68571, + "bpm": 141, + "key": { + "standard": { + "letter": "F", + "sharp": False, + "flat": False, + "chord": "major" + }, + "shortName": "Fmaj" + }, + "artists": [{ + "id": 326158, + "name": "Supersillyus", + "slug": "supersillyus", + "type": "artist" + }], + "genres": [{ + "id": 9, + "name": "Breaks", + "slug": "breaks", + "type": "genre" + }], + "subGenres": [{ + "id": 209, + "name": "Glitch Hop", + "slug": "glitch-hop", + "type": "subgenre" + }], + "release": { + "id": 1742984, + "name": "Charade", + "type": "release", + "slug": "charade" + }, + "label": { + "id": 24539, + "name": "Gravitas Recordings", + "type": "label", + "slug": "gravitas-recordings", + "status": True + } + }, { + "id": 7817570, + "type": "track", + "sku": "track-7817570", + "name": "A List of Instructions for When I'm Human", + "trackNumber": 4, + "mixName": "Original Mix", + "title": "A List of Instructions for When I'm Human (Original Mix)", + "slug": "a-list-of-instructions-for-when-im-human-original-mix", + "releaseDate": "2016-04-11", + "publishDate": "2016-04-11", + "currentStatus": "General Content", + "length": "6:57", + "lengthMs": 417913, + "bpm": 88, + "key": { + "standard": { + "letter": "A", + "sharp": False, + "flat": False, + "chord": "minor" + }, + "shortName": "Amin" + }, + "artists": [{ + "id": 326158, + "name": "Supersillyus", + "slug": "supersillyus", + "type": "artist" + }], + "genres": [{ + "id": 9, + "name": "Breaks", + "slug": "breaks", + "type": "genre" + }], + "subGenres": [{ + "id": 209, + "name": "Glitch Hop", + "slug": "glitch-hop", + "type": "subgenre" + }], + "release": { + "id": 1742984, + "name": "Charade", + "type": "release", + "slug": "charade" + }, + "label": { + "id": 24539, + "name": "Gravitas Recordings", + "type": "label", + "slug": "gravitas-recordings", + "status": True + } + }, { + "id": 7817571, + "type": "track", + "sku": "track-7817571", + "name": "The Great Shenanigan", + "trackNumber": 5, + "mixName": "Original Mix", + "title": "The Great Shenanigan (Original Mix)", + "slug": "the-great-shenanigan-original-mix", + "releaseDate": "2016-04-11", + "publishDate": "2016-04-11", + "currentStatus": "General Content", + "length": "9:49", + "lengthMs": 589875, + "bpm": 123, + "key": { + "standard": { + "letter": "E", + "sharp": False, + "flat": True, + "chord": "major" + }, + "shortName": "E♭maj" + }, + "artists": [{ + "id": 326158, + "name": "Supersillyus", + "slug": "supersillyus", + "type": "artist" + }], + "genres": [{ + "id": 9, + "name": "Breaks", + "slug": "breaks", + "type": "genre" + }], + "subGenres": [{ + "id": 209, + "name": "Glitch Hop", + "slug": "glitch-hop", + "type": "subgenre" + }], + "release": { + "id": 1742984, + "name": "Charade", + "type": "release", + "slug": "charade" + }, + "label": { + "id": 24539, + "name": "Gravitas Recordings", + "type": "label", + "slug": "gravitas-recordings", + "status": True + } + }, { + "id": 7817572, + "type": "track", + "sku": "track-7817572", + "name": "Charade", + "trackNumber": 6, + "mixName": "Original Mix", + "title": "Charade (Original Mix)", + "slug": "charade-original-mix", + "releaseDate": "2016-04-11", + "publishDate": "2016-04-11", + "currentStatus": "General Content", + "length": "7:05", + "lengthMs": 425423, + "bpm": 123, + "key": { + "standard": { + "letter": "A", + "sharp": False, + "flat": False, + "chord": "major" + }, + "shortName": "Amaj" + }, + "artists": [{ + "id": 326158, + "name": "Supersillyus", + "slug": "supersillyus", + "type": "artist" + }], + "genres": [{ + "id": 9, + "name": "Breaks", + "slug": "breaks", + "type": "genre" + }], + "subGenres": [{ + "id": 209, + "name": "Glitch Hop", + "slug": "glitch-hop", + "type": "subgenre" + }], + "release": { + "id": 1742984, + "name": "Charade", + "type": "release", + "slug": "charade" + }, + "label": { + "id": 24539, + "name": "Gravitas Recordings", + "type": "label", + "slug": "gravitas-recordings", + "status": True + } + }] + return results + + def setUp(self): + self.setup_beets() + self.load_plugins('beatport') + self.lib = library.Library(':memory:') + + # Set up 'album'. + response_release = self._make_release_response() + self.album = beatport.BeatportRelease(response_release) + + # Set up 'tracks'. + response_tracks = self._make_tracks_response() + self.tracks = [beatport.BeatportTrack(t) for t in response_tracks] + + # Set up 'test_album'. + self.test_album = self.mk_test_album() + # print(self.test_album.keys()) + + # Set up 'test_tracks' + self.test_tracks = self.test_album.items() + + def tearDown(self): + self.unload_plugins() + self.teardown_beets() + + def mk_test_album(self): + items = [_common.item() for _ in range(6)] + for item in items: + item.album = 'Charade' + item.catalognum = 'GR089' + item.label = 'Gravitas Recordings' + item.artist = 'Supersillyus' + item.year = 2016 + item.comp = False + item.label_name = 'Gravitas Recordings' + item.genre = 'Glitch Hop' + item.year = 2016 + item.month = 4 + item.day = 11 + item.mix_name = 'Original Mix' + + items[0].title = 'Mirage a Trois' + items[1].title = 'Aeon Bahamut' + items[2].title = 'Trancendental Medication' + items[3].title = 'A List of Instructions for When I\'m Human' + items[4].title = 'The Great Shenanigan' + items[5].title = 'Charade' + + items[0].length = timedelta(minutes=7, seconds=5).total_seconds() + items[1].length = timedelta(minutes=7, seconds=38).total_seconds() + items[2].length = timedelta(minutes=1, seconds=8).total_seconds() + items[3].length = timedelta(minutes=6, seconds=57).total_seconds() + items[4].length = timedelta(minutes=9, seconds=49).total_seconds() + items[5].length = timedelta(minutes=7, seconds=5).total_seconds() + + items[0].url = 'mirage-a-trois-original-mix' + items[1].url = 'aeon-bahamut-original-mix' + items[2].url = 'trancendental-medication-original-mix' + items[3].url = 'a-list-of-instructions-for-when-im-human-original-mix' + items[4].url = 'the-great-shenanigan-original-mix' + items[5].url = 'charade-original-mix' + + counter = 0 + for item in items: + counter += 1 + item.track_number = counter + + items[0].bpm = 90 + items[1].bpm = 100 + items[2].bpm = 141 + items[3].bpm = 88 + items[4].bpm = 123 + items[5].bpm = 123 + + items[0].musical_key = 'Gmin' + items[1].musical_key = 'Gmaj' + items[2].musical_key = 'Fmaj' + items[3].musical_key = 'Amin' + items[4].musical_key = 'E♭maj' + items[5].musical_key = 'Amaj' + + for item in items: + self.lib.add(item) + + album = self.lib.add_album(items) + album.store() + + return album + + # Test BeatportRelease. + def test_album_name_applied(self): + self.assertEqual(self.album.name, self.test_album['album']) + + def test_catalog_number_applied(self): + self.assertEqual(self.album.catalog_number, + self.test_album['catalognum']) + + def test_label_applied(self): + self.assertEqual(self.album.label_name, self.test_album['label']) + + def test_category_applied(self): + self.assertEqual(self.album.category, 'Release') + + def test_album_url_applied(self): + self.assertEqual(self.album.url, + 'https://beatport.com/release/charade/1742984') + + # Test BeatportTrack. + def test_title_applied(self): + for track, test_track in zip(self.tracks, self.test_tracks): + self.assertEqual(track.name, test_track.title) + + def test_mix_name_applied(self): + for track, test_track in zip(self.tracks, self.test_tracks): + self.assertEqual(track.mix_name, test_track.mix_name) + + def test_length_applied(self): + for track, test_track in zip(self.tracks, self.test_tracks): + self.assertEqual(int(track.length.total_seconds()), + int(test_track.length)) + + def test_track_url_applied(self): + # Specify beatport ids here because an 'item.id' is beets-internal. + ids = [ + 7817567, + 7817568, + 7817569, + 7817570, + 7817571, + 7817572, + ] + # Concatenate with 'id' to pass strict equality test. + for track, test_track, id in zip(self.tracks, self.test_tracks, ids): + self.assertEqual( + track.url, 'https://beatport.com/track/' + + test_track.url + '/' + six.text_type(id)) + + def test_bpm_applied(self): + for track, test_track in zip(self.tracks, self.test_tracks): + self.assertEqual(track.bpm, test_track.bpm) + + def test_musical_key_applied(self): + for track, test_track in zip(self.tracks, self.test_tracks): + self.assertEqual(track.musical_key, test_track.musical_key) + + def test_genre_applied(self): + for track, test_track in zip(self.tracks, self.test_tracks): + self.assertEqual(track.genre, test_track.genre) + + +def suite(): + return unittest.TestLoader().loadTestsFromName(__name__) + + +if __name__ == '__main__': + unittest.main(defaultTest='suite')