Some unit tests for addMany
[libmpd_haskell.git] / tests / Commands.hs
blob502f32a1c55841551e8003e15fa154dcc06e70eb
1 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
3 -- |
4 -- This module provides a way of verifying that the interface to the MPD
5 -- commands is correct. It does so by capturing the data flow between the
6 -- command and a dummy socket, checking the captured data against a set of
7 -- predefined values that are known to be correct. Of course, this does not
8 -- verify that the external behaviour is correct, it's simply a way of
9 -- catching silly mistakes and subtle bugs in the interface itself, without
10 -- having to actually send any requests to a real server.
12 module Commands (main) where
14 import Network.MPD.Commands
15 import Network.MPD.Core (Response, MPDError(..))
16 import Network.MPD.StringConn
18 import Control.Monad
19 import Prelude hiding (repeat)
20 import Text.Printf
22 main = mapM_ (\(n, f) -> f >>= \x -> printf "%-14s: %s\n" n x) tests
23 where tests = [("enableOutput", testEnableOutput)
24 ,("disableOutput", testDisableOutput)
25 ,("outputs", testOutputs)
26 ,("update0", testUpdate0)
27 ,("update1", testUpdate1)
28 ,("updateMany", testUpdateMany)
29 ,("find", testFind)
30 ,("list(Nothing)", testListNothing)
31 ,("list(Just)", testListJust)
32 ,("listAll", testListAll)
33 ,("lsInfo", testLsInfo)
34 ,("listAllInfo", testListAllInfo)
35 ,("search", testSearch)
36 ,("count", testCount)
37 ,("add", testAdd)
38 ,("add_", testAdd_)
39 ,("add_ / playlist", testAdd_pl)
40 ,("addId", testAddId)
41 ,("clear", testClear)
42 ,("plChangesPosId 0", testPlChangesPosId_0)
43 ,("plChangesPosId 1", testPlChangesPosId_1)
44 ,("plChangesPosId wierd", testPlChangesPosId_Wierd)
45 ,("currentSong(_)", testCurrentSongStopped)
46 ,("currentSong(>)", testCurrentSongPlaying)
47 ,("delete0", testDelete0)
48 ,("delete1", testDelete1)
49 ,("delete2", testDelete2)
50 ,("load", testLoad)
51 ,("move0", testMove0)
52 ,("move1", testMove1)
53 ,("move2", testMove2)
54 ,("rm", testRm)
55 ,("rename", testRename)
56 ,("save", testSave)
57 ,("swap0", testSwap0)
58 ,("swap1", testSwap1)
59 ,("shuffle", testShuffle)
60 ,("playlistInfo0", testPlaylistInfo0)
61 ,("playlistInfo / pos", testPlaylistInfoPos)
62 ,("playlistInfo / id", testPlaylistInfoId)
63 ,("listPlaylistInfo", testListPlaylistInfo)
64 ,("listPlaylist", testListPlaylist)
65 ,("playlist", testPlaylist)
66 ,("plchanges", testPlChanges)
67 ,("playlistFind", testPlaylistFind)
68 ,("playlistSearch", testPlaylistSearch)
69 ,("crossfade", testCrossfade)
70 ,("play", testPlay)
71 ,("play / pos", testPlayPos)
72 ,("play / id", testPlayId)
73 ,("pause", testPause)
74 ,("stop", testStop)
75 ,("next", testNext)
76 ,("previous", testPrevious)
77 ,("seek / pos", testSeekPos)
78 ,("seek / id", testSeekId)
79 ,("random", testRandom)
80 ,("repeat", testRepeat)
81 ,("setVolume", testSetVolume)
82 ,("volume", testVolume)
83 ,("clearError", testClearError)
84 ,("commands", testCommands)
85 ,("notCommands", testNotCommands)
86 ,("tagTypes", testTagTypes)
87 ,("urlHandlers", testUrlHandlers)
88 ,("password", testPassword)
89 ,("ping", testPing)
90 ,("stats", testStats)
91 ,("updateId0", testUpdateId0)
92 ,("updateId1", testUpdateId1)
93 ,("toggle / stop", testToggleStop)
94 ,("toggle / play", testTogglePlay)
95 ,("toggle / pause", testTogglePause)
96 ,("addMany0", testAddMany0)
97 ,("addMany1", testAddMany1)
98 ,("song parsing / incomplete track",
99 testSongParseIncompleteTrack)
100 ,("song parsing / complete track",
101 testSongParseCompleteTrack)
104 test a b c = liftM (showResult b) $ testMPD a b (return Nothing) c
106 test_ a b = test a (Right ()) b
108 showResult :: (Show a) => Response a -> Result a -> String
109 showResult _ Ok = "passed"
110 showResult expectedResult (Failure result mms) =
111 "*** FAILURE ***" ++
112 concatMap (\(x,y) -> "\n expected request: " ++ show x ++
113 "\n actual request: " ++ show y) mms ++
114 "\n expected result: " ++ show expectedResult ++
115 "\n actual result: " ++ show result
117 emptySong = Song { sgArtist = ""
118 , sgAlbum = ""
119 , sgTitle = ""
120 , sgFilePath = ""
121 , sgGenre = ""
122 , sgName = ""
123 , sgComposer = ""
124 , sgPerformer = ""
125 , sgLength = 0
126 , sgDate = 0
127 , sgTrack = (0,0)
128 , sgDisc = (0,0)
129 , sgIndex = Nothing }
132 -- Parser behaviour.
133 -- These tests are meant to expose problems with internal
134 -- parsers.
137 -- Should handle track = 'X'.
138 testSongParseIncompleteTrack =
139 test [("find Artist \"Foo\"", Right "file: dir/Foo-Bar.ogg\n\
140 \Track: 1\n\
141 \OK")]
142 (Right [emptySong { sgTrack = (1,1)
143 , sgFilePath = "dir/Foo-Bar.ogg"
145 (find $ Query Artist "Foo")
147 -- Should handle track = 'X/Y'.
148 testSongParseCompleteTrack =
149 test [("find Artist \"Foo\"", Right "file: dir/Foo-Bar.ogg\n\
150 \Track: 2/12\n\
151 \OK")]
152 (Right [emptySong { sgTrack = (2,12)
153 , sgFilePath = "dir/Foo-Bar.ogg"
155 (find $ Query Artist "Foo")
158 -- Admin commands
161 testEnableOutput = test_ [("enableoutput 1", Right "OK")] (enableOutput 1)
163 testDisableOutput = test_ [("disableoutput 1", Right "OK")] (disableOutput 1)
165 testOutputs =
166 test [("outputs", Right $ unlines ["outputid: 0"
167 ,"outputname: SoundCard0"
168 ,"outputenabled: 1"
169 ,"outputid: 1"
170 ,"outputname: SoundCard1"
171 ,"outputenabled: 0"
172 ,"OK"])]
173 (Right [Device { dOutputID = 0
174 , dOutputName = "SoundCard0"
175 , dOutputEnabled = True }
176 ,Device { dOutputID = 1
177 , dOutputName = "SoundCard1"
178 , dOutputEnabled = False }])
179 outputs
181 testUpdate0 = test_ [("update", Right "updating_db: 1\nOK")] (update [])
183 testUpdate1 =
184 test_ [("update \"foo\"", Right "updating_db: 1\nOK")]
185 (update ["foo"])
187 testUpdateMany =
188 test_ [("command_list_begin\nupdate \"foo\"\nupdate \"bar\"\n\
189 \command_list_end", Right "updating_db: 1\nOK")]
190 (update ["foo","bar"])
193 -- Database commands
196 testFind =
197 test [("find Artist \"Foo\"", Right "file: dir/Foo-Bar.ogg\n\
198 \Time: 60\n\
199 \Artist: Foo\n\
200 \Title: Bar\n\
201 \OK")]
202 (Right [Song { sgArtist = "Foo"
203 , sgAlbum = ""
204 , sgTitle = "Bar"
205 , sgFilePath = "dir/Foo-Bar.ogg"
206 , sgGenre = ""
207 , sgName = ""
208 , sgComposer = ""
209 , sgPerformer = ""
210 , sgLength = 60
211 , sgDate = 0
212 , sgTrack = (0,0)
213 , sgDisc = (0,0)
214 , sgIndex = Nothing
216 (find (Query Artist "Foo"))
218 testListNothing =
219 test [("list Title", Right "Title: Foo\nTitle: Bar\nOK")]
220 (Right ["Foo", "Bar"])
221 (list Title Nothing)
223 testListJust =
224 test [("list Title Artist \"Muzz\"", Right "Title: Foo\nOK")]
225 (Right ["Foo"])
226 (list Title (Just $ Query Artist "Muzz"))
228 testListAll =
229 test [("listall \"\"", Right "directory: FooBand\n\
230 \directory: FooBand/album1\n\
231 \file: FooBand/album1/01 - songA.ogg\n\
232 \file: FooBand/album1/02 - songB.ogg\nOK")]
233 (Right ["FooBand/album1/01 - songA.ogg"
234 ,"FooBand/album1/02 - songB.ogg"])
235 (listAll "")
237 testLsInfo =
238 test [("lsinfo \"\"", Right "directory: Foo\ndirectory: Bar\nOK")]
239 (Right [Left "Bar", Left "Foo"])
240 (lsInfo "")
242 testListAllInfo =
243 test [("listallinfo \"\"", Right "directory: Foo\ndirectory: Bar\nOK")]
244 (Right [Left "Bar", Left "Foo"])
245 (listAllInfo "")
247 testSearch =
248 test [("search Artist \"oo\"", Right "file: dir/Foo-Bar.ogg\n\
249 \Time: 60\n\
250 \Artist: Foo\n\
251 \Title: Bar\n\
252 \OK")]
253 (Right [Song { sgArtist = "Foo"
254 , sgAlbum = ""
255 , sgTitle = "Bar"
256 , sgFilePath = "dir/Foo-Bar.ogg"
257 , sgGenre = ""
258 , sgName = ""
259 , sgComposer = ""
260 , sgPerformer = ""
261 , sgLength = 60
262 , sgDate = 0
263 , sgTrack = (0,0)
264 , sgDisc = (0,0)
265 , sgIndex = Nothing
267 (search (Query Artist "oo"))
269 testCount =
270 test [("count Title \"Foo\"", Right "songs: 1\nplaytime: 60\nOK")]
271 (Right (Count 1 60))
272 (count (Query Title "Foo"))
275 -- Playlist commands
278 testAdd =
279 test [("add \"foo\"", Right "OK"),
280 ("listall \"foo\"", Right "file: Foo\nfile: Bar\nOK")]
281 (Right ["Foo", "Bar"])
282 (add "" "foo")
284 testAdd_ = test_ [("add \"foo\"", Right "OK")] (add_ "" "foo")
286 testAdd_pl = test_ [("playlistadd \"foo\" \"bar\"", Right "OK")]
287 (add_ "foo" "bar")
289 testAddId =
290 test [("addid \"dir/Foo-Bar.ogg\"", Right "Id: 20\nOK")]
291 (Right 20)
292 (addId "dir/Foo-Bar.ogg")
294 testClear = test_ [("playlistclear \"foo\"", Right "OK")] (clear "foo")
296 testPlChangesPosId_0 =
297 test [("plchangesposid 10", Right "OK")]
298 (Right [])
299 (plChangesPosId 10)
301 testPlChangesPosId_1 =
302 test [("plchangesposid 10", Right "cpos: 0\nId: 20\nOK")]
303 (Right [(Pos 0, ID 20)])
304 (plChangesPosId 10)
306 testPlChangesPosId_Wierd =
307 test [("plchangesposid 10", Right "cpos: foo\nId: bar\nOK")]
308 (Left $ Unexpected "[(\"cpos\",\"foo\"),(\"Id\",\"bar\")]")
309 (plChangesPosId 10)
311 testCurrentSongStopped =
312 test [("status", Right "repeat: 0\n\
313 \random: 0\n\
314 \playlist: 253\n\
315 \playlistlength: 0\n\
316 \xfade: 0\n\
317 \state: stop\nOK")]
318 (Right Nothing)
319 (currentSong)
321 testCurrentSongPlaying =
322 test [("status", Right "volume: 80\n\
323 \repeat: 0\n\
324 \random: 0\n\
325 \playlist: 252\n\
326 \playlistlength: 21\n\
327 \xfade: 0\n\
328 \state: play\n\
329 \song: 20\n\
330 \songid: 238\n\
331 \time: 158:376\n\
332 \bitrate: 192\n\
333 \audio: 44100:16:2\n\
334 \OK")
335 ,("currentsong", Right "file: dir/Foo-Bar.ogg\n\
336 \Time: 60\n\
337 \Artist: Foo\n\
338 \Title: Bar\n\
339 \OK")]
340 (Right . Just $ Song { sgArtist = "Foo"
341 , sgAlbum = ""
342 , sgTitle = "Bar"
343 , sgFilePath = "dir/Foo-Bar.ogg"
344 , sgGenre = ""
345 , sgName = ""
346 , sgComposer = ""
347 , sgPerformer = ""
348 , sgLength = 60
349 , sgDate = 0
350 , sgTrack = (0,0)
351 , sgDisc = (0,0)
352 , sgIndex = Nothing
354 (currentSong)
356 testDelete0 = test_ [("delete 1", Right "OK")] (delete "" (Pos 1))
358 testDelete1 = test_ [("deleteid 1", Right "OK")] (delete "" (ID 1))
360 testDelete2 = test_ [("playlistdelete \"foo\" 1", Right "OK")] (delete "foo" (Pos 1))
362 testLoad = test_ [("load \"foo\"", Right "OK")] (load "foo")
364 testMove0 = test_ [("move 1 2", Right "OK")] (move "" (Pos 1) 2)
366 testMove1 = test_ [("moveid 1 2", Right "OK")] (move "" (ID 1) 2)
368 testMove2 = test_ [("playlistmove \"foo\" 1 2", Right "OK")] (move "foo" (Pos 1) 2)
370 testRm = test_ [("rm \"foo\"", Right "OK")] (rm "foo")
372 testRename = test_ [("rename \"foo\" \"bar\"", Right "OK")] (rename "foo" "bar")
374 testSave = test_ [("save \"foo\"", Right "OK")] (save "foo")
376 testSwap0 = test_ [("swap 1 2", Right "OK")] (swap (Pos 1) (Pos 2))
378 testSwap1 = test_ [("swapid 1 2", Right "OK")] (swap (ID 1) (ID 2))
380 testShuffle = test_ [("shuffle", Right "OK")] shuffle
382 testPlaylistInfo0 = test [("playlistinfo", Right "file: dir/Foo-Bar.ogg\n\
383 \Time: 60\n\
384 \Artist: Foo\n\
385 \Title: Bar\n\
386 \OK")]
387 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
388 , sgLength = 60
389 , sgArtist = "Foo"
390 , sgTitle = "Bar" }])
391 (playlistInfo Nothing)
393 testPlaylistInfoPos = test [("playlistinfo 1", Right "file: dir/Foo-Bar.ogg\n\
394 \Time: 60\n\
395 \Artist: Foo\n\
396 \Title: Bar\n\
397 \OK")]
398 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
399 , sgLength = 60
400 , sgArtist = "Foo"
401 , sgTitle = "Bar" }])
402 (playlistInfo . Just $ Pos 1)
404 testPlaylistInfoId = test [("playlistid 1", Right "file: dir/Foo-Bar.ogg\n\
405 \Time: 60\n\
406 \Artist: Foo\n\
407 \Title: Bar\n\
408 \OK")]
409 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
410 , sgLength = 60
411 , sgArtist = "Foo"
412 , sgTitle = "Bar" }])
413 (playlistInfo . Just $ ID 1)
415 testListPlaylistInfo = test [("listplaylistinfo \"foo\""
416 ,Right "file: dir/Foo-Bar.ogg\n\
417 \Time: 60\n\
418 \Artist: Foo\n\
419 \Title: Bar\n\
420 \OK")]
421 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
422 , sgLength = 60
423 , sgArtist = "Foo"
424 , sgTitle = "Bar" }])
425 (listPlaylistInfo "foo")
427 testListPlaylist = test [("listplaylist \"foo\""
428 ,Right "file: dir/Foo-bar.ogg\n\
429 \file: dir/Quux-quuz.ogg\n\
430 \OK")]
431 (Right ["dir/Foo-bar.ogg", "dir/Quux-quuz.ogg"])
432 (listPlaylist "foo")
434 testPlaylist = test [("playlist"
435 ,Right "1:Foo.ogg\n\
436 \2:Bar.ogg\n\
437 \OK")]
438 (Right [(Pos 1, "Foo.ogg")
439 ,(Pos 2, "Bar.ogg")])
440 playlist
442 testPlChanges = test [("plchanges 0"
443 ,Right "file: foo/bar.ogg\n\
444 \Artist: Foo\n\
445 \Title: Bar\n\
446 \OK")]
447 (Right [emptySong { sgArtist = "Foo"
448 , sgTitle = "Bar"
449 , sgFilePath = "foo/bar.ogg" }])
450 (plChanges 0)
452 testPlaylistFind = test [("playlistfind Artist \"Foo\""
453 ,Right "file: dir/Foo/Bar.ogg\n\
454 \Artist: Foo\n\
455 \OK")]
456 (Right [emptySong { sgFilePath = "dir/Foo/Bar.ogg"
457 , sgArtist = "Foo" }])
458 (playlistFind $ Query Artist "Foo")
460 testPlaylistSearch = test [("playlistsearch Artist \"Foo\""
461 ,Right "file: dir/Foo/Bar.ogg\n\
462 \Artist: Foo\n\
463 \OK")]
464 (Right [emptySong { sgFilePath = "dir/Foo/Bar.ogg"
465 , sgArtist = "Foo" }])
466 (playlistSearch $ Query Artist "Foo")
469 -- Playback commands
472 testCrossfade = test_ [("crossfade 0", Right "OK")] (crossfade 0)
474 testPlay = test_ [("play", Right "OK")] (play Nothing)
476 testPlayPos = test_ [("play 1", Right "OK")] (play . Just $ Pos 1)
478 testPlayId = test_ [("playid 1", Right "OK")] (play . Just $ ID 1)
480 testPause = test_ [("pause 0", Right "OK")] (pause False)
482 testStop = test_ [("stop", Right "OK")] stop
484 testNext = test_ [("next", Right "OK")] next
486 testPrevious = test_ [("previous", Right "OK")] previous
488 testSeekPos = test_ [("seek 1 10", Right "OK")] (seek (Just $ Pos 1) 10)
490 testSeekId = test_ [("seekid 1 10", Right "OK")] (seek (Just $ ID 1) 10)
492 testRandom = test_ [("random 0", Right "OK")] (random False)
494 testRepeat = test_ [("repeat 0", Right "OK")] (repeat False)
496 testSetVolume = test_ [("setvol 10", Right "OK")] (setVolume 10)
498 testVolume = test_ [("volume 10", Right "OK")] (volume 10)
501 -- Miscellaneous commands
504 testClearError = test_ [("clearerror", Right "OK")] clearError
506 testCommands =
507 test [("commands", Right "command: foo\ncommand: bar")]
508 (Right ["foo", "bar"])
509 commands
511 testNotCommands =
512 test [("notcommands", Right "command: foo\ncommand: bar")]
513 (Right ["foo", "bar"])
514 notCommands
516 testTagTypes =
517 test [("tagtypes", Right "tagtype: foo\ntagtype: bar")]
518 (Right ["foo", "bar"])
519 tagTypes
521 testUrlHandlers =
522 test [("urlhandlers", Right "urlhandler: foo\nurlhandler: bar")]
523 (Right ["foo", "bar"])
524 urlHandlers
526 testPassword = test_ [("password foo", Right "OK")] (password "foo")
528 testPing = test_ [("ping", Right "OK")] ping
530 testStats = test [("stats", Right "artists: 1\n\
531 \albums: 1\n\
532 \songs: 1\n\
533 \uptime: 100\n\
534 \playtime: 100\n\
535 \db_playtime: 100\n\
536 \db_update: 10\n\
537 \OK")]
538 (Right Stats { stsArtists = 1, stsAlbums = 1, stsSongs = 1
539 , stsUptime = 100, stsPlaytime = 100, stsDbUpdate = 10
540 , stsDbPlaytime = 100 })
541 stats
544 -- Extensions\/shortcuts
547 testUpdateId0 = test [("update", Right "updating_db: 1")]
548 (Right 1)
549 (updateId [])
551 testUpdateId1 = test [("update \"foo\"", Right "updating_db: 1")]
552 (Right 1)
553 (updateId ["foo"])
555 testTogglePlay = test_
556 [("status", Right "state: play")
557 ,("pause 1", Right "OK")]
558 toggle
560 testToggleStop = test_
561 [("status", Right "state: stop")
562 ,("play", Right "OK")]
563 toggle
565 testTogglePause = test_
566 [("status", Right "state: pause")
567 ,("play", Right "OK")]
568 toggle
570 testAddMany0 = test_ [("add \"bar\"", Right "OK")]
571 (addMany "" ["bar"])
573 testAddMany1 = test_ [("playlistadd \"foo\" \"bar\"", Right "OK")]
574 (addMany "foo" ["bar"])