{"action":"created","comment":{"url":"https://api.github.com/repos/mopidy/mopidy/pulls/comments/43386344","id":43386344,"diff_hunk":"@@ -211,29 +211,95 @@ def test_load_unknown_playlist_acks(self):\n         self.assertEqualResponse('ACK [50@0] {load} No such playlist')\n \n     def test_playlistadd(self):\n+        tracks = [\n+            Track(uri='dummy:a'),\n+            Track(uri='dummy:b'),\n+        ]\n+        self.backend.library.dummy_library = tracks\n+        self.backend.playlists.set_dummy_playlists([\n+            Playlist(\n+                name='name', uri='dummy:a1', tracks=[tracks[0]])])\n+        self.send_request('playlistadd \"name\" \"dummy:b\"')\n+        self.assertInResponse('OK')\n+        self.assertEqual(\n+            2, len(self.backend.playlists.get_items(\"dummy:a1\").get()))\n+\n+    def test_playlistadd_creates_playlist(self):\n+        tracks = [\n+            Track(uri='dummy:a'),\n+        ]\n+        self.backend.library.dummy_library = tracks\n         self.send_request('playlistadd \"name\" \"dummy:a\"')\n-        self.assertEqualResponse('ACK [0@0] {playlistadd} Not implemented')\n+        self.assertInResponse('OK')\n+        self.assertNotEqual(\n+            None, self.backend.playlists.lookup(\"dummy:name\").get())\n \n     def test_playlistclear(self):\n+        self.backend.playlists.set_dummy_playlists([\n+            Playlist(\n+                name='name', uri='dummy:a1', tracks=[Track(uri='b')])])\n+\n         self.send_request('playlistclear \"name\"')\n-        self.assertEqualResponse('ACK [0@0] {playlistclear} Not implemented')\n+        self.assertInResponse('OK')\n+        self.assertEqual(\n+            0, len(self.backend.playlists.get_items(\"dummy:a1\").get()))\n+\n+    def test_playlistclear_creates_playlist(self):\n+        self.send_request('playlistclear \"name\"')\n+        self.assertInResponse('OK')\n+        self.assertNotEqual(\n+            None, self.backend.playlists.lookup(\"dummy:name\").get())\n \n     def test_playlistdelete(self):\n-        self.send_request('playlistdelete \"name\" \"5\"')\n-        self.assertEqualResponse('ACK [0@0] {playlistdelete} Not implemented')\n+        tracks = [\n+            Track(uri='dummy:a'),\n+            Track(uri='dummy:b'),\n+            Track(uri='dummy:c'),\n+        ]   # len() == 3\n+        self.backend.playlists.set_dummy_playlists([\n+            Playlist(\n+                name='name', uri='dummy:a1', tracks=tracks)])\n+\n+        self.send_request('playlistdelete \"name\" \"2\"')\n+        self.assertInResponse('OK')\n+        self.assertEqual(\n+            2, len(self.backend.playlists.get_items(\"dummy:a1\").get()))\n \n     def test_playlistmove(self):\n-        self.send_request('playlistmove \"name\" \"5\" \"10\"')\n-        self.assertEqualResponse('ACK [0@0] {playlistmove} Not implemented')\n+        tracks = [\n+            Track(uri='dummy:a'),\n+            Track(uri='dummy:b'),\n+            Track(uri='dummy:c')    # this one is getting moved to top\n+        ]\n+        self.backend.playlists.set_dummy_playlists([\n+            Playlist(\n+                name='name', uri='dummy:a1', tracks=tracks)])\n+        self.send_request('playlistmove \"name\" \"2\" \"0\"')\n+        self.assertInResponse('OK')\n+        self.assertEqual(\n+            \"dummy:c\",\n+            self.backend.playlists.get_items(\"dummy:a1\").get()[0].uri)\n \n     def test_rename(self):\n+        self.backend.playlists.set_dummy_playlists([\n+            Playlist(\n+                name='old_name', uri='dummy:a1', tracks=[Track(uri='b')])])\n         self.send_request('rename \"old_name\" \"new_name\"')\n-        self.assertEqualResponse('ACK [0@0] {rename} Not implemented')\n+        self.assertInResponse('OK')\n+        self.assertNotEqual(\n+            None, self.backend.playlists.lookup(\"dummy:new_name\").get())\n \n     def test_rm(self):\n+        self.backend.playlists.set_dummy_playlists([\n+            Playlist(\n+                name='name', uri='dummy:a1', tracks=[Track(uri='b')])])\n         self.send_request('rm \"name\"')\n-        self.assertEqualResponse('ACK [0@0] {rm} Not implemented')\n+        self.assertInResponse('OK')\n+        self.assertEqual(\n+            None, self.backend.playlists.lookup(\"dummy:a1\").get())","path":"tests/mpd/protocol/test_stored_playlists.py","position":97,"original_position":97,"commit_id":"b44af7e5617c9ce7788e7ec4e5c2f7a0353b058f","original_commit_id":"b44af7e5617c9ce7788e7ec4e5c2f7a0353b058f","user":{"login":"jodal","id":43726,"avatar_url":"https://avatars.githubusercontent.com/u/43726?v=3","gravatar_id":"","url":"https://api.github.com/users/jodal","html_url":"https://github.com/jodal","followers_url":"https://api.github.com/users/jodal/followers","following_url":"https://api.github.com/users/jodal/following{/other_user}","gists_url":"https://api.github.com/users/jodal/gists{/gist_id}","starred_url":"https://api.github.com/users/jodal/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jodal/subscriptions","organizations_url":"https://api.github.com/users/jodal/orgs","repos_url":"https://api.github.com/users/jodal/repos","events_url":"https://api.github.com/users/jodal/events{/privacy}","received_events_url":"https://api.github.com/users/jodal/received_events","type":"User","site_admin":false},"body":"I've used `assertIsNone()` and `assertIsNotNone()` where applicable.","created_at":"2015-10-29T13:53:22Z","updated_at":"2015-10-29T13:53:22Z","html_url":"https://github.com/mopidy/mopidy/pull/1187#discussion_r43386344","pull_request_url":"https://api.github.com/repos/mopidy/mopidy/pulls/1187","_links":{"self":{"href":"https://api.github.com/repos/mopidy/mopidy/pulls/comments/43386344"},"html":{"href":"https://github.com/mopidy/mopidy/pull/1187#discussion_r43386344"},"pull_request":{"href":"https://api.github.com/repos/mopidy/mopidy/pulls/1187"}}},"pull_request":{"url":"https://api.github.com/repos/mopidy/mopidy/pulls/1187","id":35886204,"html_url":"https://github.com/mopidy/mopidy/pull/1187","diff_url":"https://github.com/mopidy/mopidy/pull/1187.diff","patch_url":"https://github.com/mopidy/mopidy/pull/1187.patch","issue_url":"https://api.github.com/repos/mopidy/mopidy/issues/1187","number":1187,"state":"open","locked":false,"title":"mpd: Implemetation for commands related to modifying stored playlists.","user":{"login":"kozec","id":1282500,"avatar_url":"https://avatars.githubusercontent.com/u/1282500?v=3","gravatar_id":"","url":"https://api.github.com/users/kozec","html_url":"https://github.com/kozec","followers_url":"https://api.github.com/users/kozec/followers","following_url":"https://api.github.com/users/kozec/following{/other_user}","gists_url":"https://api.github.com/users/kozec/gists{/gist_id}","starred_url":"https://api.github.com/users/kozec/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kozec/subscriptions","organizations_url":"https://api.github.com/users/kozec/orgs","repos_url":"https://api.github.com/users/kozec/repos","events_url":"https://api.github.com/users/kozec/events{/privacy}","received_events_url":"https://api.github.com/users/kozec/received_events","type":"User","site_admin":false},"body":"This PR implements all missing commands from `mpd/protocol/stored_playlists.py`. It turned out to be rather simple, so I just hope I didn't overlooked anything big.\r\n\r\nMain problem can be in fe8bb5114e9969f328e66f9d3be722f523ae51f3. Event on delete is important for MPD clients, but if anything else relies on playlist to be valid object instead of None, this change may break it.\r\n\r\nI've tested implementation with GMPC, Cantana and MPDroid.","created_at":"2015-05-20T23:19:02Z","updated_at":"2015-10-29T13:53:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f05f56e3ef505a5986f7c5ff842be3c280b9dce8","assignee":{"login":"jodal","id":43726,"avatar_url":"https://avatars.githubusercontent.com/u/43726?v=3","gravatar_id":"","url":"https://api.github.com/users/jodal","html_url":"https://github.com/jodal","followers_url":"https://api.github.com/users/jodal/followers","following_url":"https://api.github.com/users/jodal/following{/other_user}","gists_url":"https://api.github.com/users/jodal/gists{/gist_id}","starred_url":"https://api.github.com/users/jodal/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jodal/subscriptions","organizations_url":"https://api.github.com/users/jodal/orgs","repos_url":"https://api.github.com/users/jodal/repos","events_url":"https://api.github.com/users/jodal/events{/privacy}","received_events_url":"https://api.github.com/users/jodal/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/mopidy/mopidy/milestones/45","html_url":"https://github.com/mopidy/mopidy/milestones/v1.2%20-%20Gapless","labels_url":"https://api.github.com/repos/mopidy/mopidy/milestones/45/labels","id":1084268,"number":45,"title":"v1.2 - Gapless","description":"\r\n\r\n<!---\r\n@huboard:{\"order\":32.1875}\r\n-->\r\n","creator":{"login":"adamcik","id":82534,"avatar_url":"https://avatars.githubusercontent.com/u/82534?v=3","gravatar_id":"","url":"https://api.github.com/users/adamcik","html_url":"https://github.com/adamcik","followers_url":"https://api.github.com/users/adamcik/followers","following_url":"https://api.github.com/users/adamcik/following{/other_user}","gists_url":"https://api.github.com/users/adamcik/gists{/gist_id}","starred_url":"https://api.github.com/users/adamcik/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/adamcik/subscriptions","organizations_url":"https://api.github.com/users/adamcik/orgs","repos_url":"https://api.github.com/users/adamcik/repos","events_url":"https://api.github.com/users/adamcik/events{/privacy}","received_events_url":"https://api.github.com/users/adamcik/received_events","type":"User","site_admin":false},"open_issues":23,"closed_issues":11,"state":"open","created_at":"2015-04-26T22:08:42Z","updated_at":"2015-10-29T13:44:39Z","due_on":"2016-03-31T22:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/mopidy/mopidy/pulls/1187/commits","review_comments_url":"https://api.github.com/repos/mopidy/mopidy/pulls/1187/comments","review_comment_url":"https://api.github.com/repos/mopidy/mopidy/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mopidy/mopidy/issues/1187/comments","statuses_url":"https://api.github.com/repos/mopidy/mopidy/statuses/b44af7e5617c9ce7788e7ec4e5c2f7a0353b058f","head":{"label":"kozec:missing-mpd-commands","ref":"missing-mpd-commands","sha":"b44af7e5617c9ce7788e7ec4e5c2f7a0353b058f","user":{"login":"kozec","id":1282500,"avatar_url":"https://avatars.githubusercontent.com/u/1282500?v=3","gravatar_id":"","url":"https://api.github.com/users/kozec","html_url":"https://github.com/kozec","followers_url":"https://api.github.com/users/kozec/followers","following_url":"https://api.github.com/users/kozec/following{/other_user}","gists_url":"https://api.github.com/users/kozec/gists{/gist_id}","starred_url":"https://api.github.com/users/kozec/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kozec/subscriptions","organizations_url":"https://api.github.com/users/kozec/orgs","repos_url":"https://api.github.com/users/kozec/repos","events_url":"https://api.github.com/users/kozec/events{/privacy}","received_events_url":"https://api.github.com/users/kozec/received_events","type":"User","site_admin":false},"repo":{"id":35970065,"name":"mopidy","full_name":"kozec/mopidy","owner":{"login":"kozec","id":1282500,"avatar_url":"https://avatars.githubusercontent.com/u/1282500?v=3","gravatar_id":"","url":"https://api.github.com/users/kozec","html_url":"https://github.com/kozec","followers_url":"https://api.github.com/users/kozec/followers","following_url":"https://api.github.com/users/kozec/following{/other_user}","gists_url":"https://api.github.com/users/kozec/gists{/gist_id}","starred_url":"https://api.github.com/users/kozec/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kozec/subscriptions","organizations_url":"https://api.github.com/users/kozec/orgs","repos_url":"https://api.github.com/users/kozec/repos","events_url":"https://api.github.com/users/kozec/events{/privacy}","received_events_url":"https://api.github.com/users/kozec/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/kozec/mopidy","description":"Mopidy is an extensible music server that plays music from local disk, Spotify, SoundCloud, Google Play Music, and more. You edit the playlist from any phone, tablet, or computer using a range of MPD and web clients.","fork":true,"url":"https://api.github.com/repos/kozec/mopidy","forks_url":"https://api.github.com/repos/kozec/mopidy/forks","keys_url":"https://api.github.com/repos/kozec/mopidy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kozec/mopidy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kozec/mopidy/teams","hooks_url":"https://api.github.com/repos/kozec/mopidy/hooks","issue_events_url":"https://api.github.com/repos/kozec/mopidy/issues/events{/number}","events_url":"https://api.github.com/repos/kozec/mopidy/events","assignees_url":"https://api.github.com/repos/kozec/mopidy/assignees{/user}","branches_url":"https://api.github.com/repos/kozec/mopidy/branches{/branch}","tags_url":"https://api.github.com/repos/kozec/mopidy/tags","blobs_url":"https://api.github.com/repos/kozec/mopidy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kozec/mopidy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kozec/mopidy/git/refs{/sha}","trees_url":"https://api.github.com/repos/kozec/mopidy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kozec/mopidy/statuses/{sha}","languages_url":"https://api.github.com/repos/kozec/mopidy/languages","stargazers_url":"https://api.github.com/repos/kozec/mopidy/stargazers","contributors_url":"https://api.github.com/repos/kozec/mopidy/contributors","subscribers_url":"https://api.github.com/repos/kozec/mopidy/subscribers","subscription_url":"https://api.github.com/repos/kozec/mopidy/subscription","commits_url":"https://api.github.com/repos/kozec/mopidy/commits{/sha}","git_commits_url":"https://api.github.com/repos/kozec/mopidy/git/commits{/sha}","comments_url":"https://api.github.com/repos/kozec/mopidy/comments{/number}","issue_comment_url":"https://api.github.com/repos/kozec/mopidy/issues/comments{/number}","contents_url":"https://api.github.com/repos/kozec/mopidy/contents/{+path}","compare_url":"https://api.github.com/repos/kozec/mopidy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kozec/mopidy/merges","archive_url":"https://api.github.com/repos/kozec/mopidy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kozec/mopidy/downloads","issues_url":"https://api.github.com/repos/kozec/mopidy/issues{/number}","pulls_url":"https://api.github.com/repos/kozec/mopidy/pulls{/number}","milestones_url":"https://api.github.com/repos/kozec/mopidy/milestones{/number}","notifications_url":"https://api.github.com/repos/kozec/mopidy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kozec/mopidy/labels{/name}","releases_url":"https://api.github.com/repos/kozec/mopidy/releases{/id}","created_at":"2015-05-20T19:38:31Z","updated_at":"2015-05-20T19:38:32Z","pushed_at":"2015-07-12T12:55:44Z","git_url":"git://github.com/kozec/mopidy.git","ssh_url":"git@github.com:kozec/mopidy.git","clone_url":"https://github.com/kozec/mopidy.git","svn_url":"https://github.com/kozec/mopidy","homepage":"www.mopidy.com","size":18633,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"develop"}},"base":{"label":"mopidy:develop","ref":"develop","sha":"a99e161aab413a3b7060ce1964c5adf1352baf33","user":{"login":"mopidy","id":451998,"avatar_url":"https://avatars.githubusercontent.com/u/451998?v=3","gravatar_id":"","url":"https://api.github.com/users/mopidy","html_url":"https://github.com/mopidy","followers_url":"https://api.github.com/users/mopidy/followers","following_url":"https://api.github.com/users/mopidy/following{/other_user}","gists_url":"https://api.github.com/users/mopidy/gists{/gist_id}","starred_url":"https://api.github.com/users/mopidy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mopidy/subscriptions","organizations_url":"https://api.github.com/users/mopidy/orgs","repos_url":"https://api.github.com/users/mopidy/repos","events_url":"https://api.github.com/users/mopidy/events{/privacy}","received_events_url":"https://api.github.com/users/mopidy/received_events","type":"Organization","site_admin":false},"repo":{"id":447036,"name":"mopidy","full_name":"mopidy/mopidy","owner":{"login":"mopidy","id":451998,"avatar_url":"https://avatars.githubusercontent.com/u/451998?v=3","gravatar_id":"","url":"https://api.github.com/users/mopidy","html_url":"https://github.com/mopidy","followers_url":"https://api.github.com/users/mopidy/followers","following_url":"https://api.github.com/users/mopidy/following{/other_user}","gists_url":"https://api.github.com/users/mopidy/gists{/gist_id}","starred_url":"https://api.github.com/users/mopidy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mopidy/subscriptions","organizations_url":"https://api.github.com/users/mopidy/orgs","repos_url":"https://api.github.com/users/mopidy/repos","events_url":"https://api.github.com/users/mopidy/events{/privacy}","received_events_url":"https://api.github.com/users/mopidy/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mopidy/mopidy","description":"Mopidy is an extensible music server that plays music from local disk, Spotify, SoundCloud, Google Play Music, and more. You edit the playlist from any phone, tablet, or computer using a range of MPD and web clients.","fork":false,"url":"https://api.github.com/repos/mopidy/mopidy","forks_url":"https://api.github.com/repos/mopidy/mopidy/forks","keys_url":"https://api.github.com/repos/mopidy/mopidy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mopidy/mopidy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mopidy/mopidy/teams","hooks_url":"https://api.github.com/repos/mopidy/mopidy/hooks","issue_events_url":"https://api.github.com/repos/mopidy/mopidy/issues/events{/number}","events_url":"https://api.github.com/repos/mopidy/mopidy/events","assignees_url":"https://api.github.com/repos/mopidy/mopidy/assignees{/user}","branches_url":"https://api.github.com/repos/mopidy/mopidy/branches{/branch}","tags_url":"https://api.github.com/repos/mopidy/mopidy/tags","blobs_url":"https://api.github.com/repos/mopidy/mopidy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mopidy/mopidy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mopidy/mopidy/git/refs{/sha}","trees_url":"https://api.github.com/repos/mopidy/mopidy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mopidy/mopidy/statuses/{sha}","languages_url":"https://api.github.com/repos/mopidy/mopidy/languages","stargazers_url":"https://api.github.com/repos/mopidy/mopidy/stargazers","contributors_url":"https://api.github.com/repos/mopidy/mopidy/contributors","subscribers_url":"https://api.github.com/repos/mopidy/mopidy/subscribers","subscription_url":"https://api.github.com/repos/mopidy/mopidy/subscription","commits_url":"https://api.github.com/repos/mopidy/mopidy/commits{/sha}","git_commits_url":"https://api.github.com/repos/mopidy/mopidy/git/commits{/sha}","comments_url":"https://api.github.com/repos/mopidy/mopidy/comments{/number}","issue_comment_url":"https://api.github.com/repos/mopidy/mopidy/issues/comments{/number}","contents_url":"https://api.github.com/repos/mopidy/mopidy/contents/{+path}","compare_url":"https://api.github.com/repos/mopidy/mopidy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mopidy/mopidy/merges","archive_url":"https://api.github.com/repos/mopidy/mopidy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mopidy/mopidy/downloads","issues_url":"https://api.github.com/repos/mopidy/mopidy/issues{/number}","pulls_url":"https://api.github.com/repos/mopidy/mopidy/pulls{/number}","milestones_url":"https://api.github.com/repos/mopidy/mopidy/milestones{/number}","notifications_url":"https://api.github.com/repos/mopidy/mopidy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mopidy/mopidy/labels{/name}","releases_url":"https://api.github.com/repos/mopidy/mopidy/releases{/id}","created_at":"2009-12-23T14:25:36Z","updated_at":"2015-10-29T06:53:38Z","pushed_at":"2015-10-29T03:29:53Z","git_url":"git://github.com/mopidy/mopidy.git","ssh_url":"git@github.com:mopidy/mopidy.git","clone_url":"https://github.com/mopidy/mopidy.git","svn_url":"https://github.com/mopidy/mopidy","homepage":"www.mopidy.com","size":27701,"stargazers_count":2292,"watchers_count":2292,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":276,"mirror_url":null,"open_issues_count":154,"forks":276,"open_issues":154,"watchers":2292,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/mopidy/mopidy/pulls/1187"},"html":{"href":"https://github.com/mopidy/mopidy/pull/1187"},"issue":{"href":"https://api.github.com/repos/mopidy/mopidy/issues/1187"},"comments":{"href":"https://api.github.com/repos/mopidy/mopidy/issues/1187/comments"},"review_comments":{"href":"https://api.github.com/repos/mopidy/mopidy/pulls/1187/comments"},"review_comment":{"href":"https://api.github.com/repos/mopidy/mopidy/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mopidy/mopidy/pulls/1187/commits"},"statuses":{"href":"https://api.github.com/repos/mopidy/mopidy/statuses/b44af7e5617c9ce7788e7ec4e5c2f7a0353b058f"}}}}