[gitconv @ Unit test for listPlaylist]
[libmpd-haskell.git] / tests / Commands.hs
blob4b5752efcd13a30594d42edaff043ed7f89879c4
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 ,("addId", testAddId)
40 ,("clear", testClear)
41 ,("plChangesPosId 0", testPlChangesPosId_0)
42 ,("plChangesPosId 1", testPlChangesPosId_1)
43 ,("plChangesPosId wierd", testPlChangesPosId_Wierd)
44 ,("currentSong(_)", testCurrentSongStopped)
45 ,("currentSong(>)", testCurrentSongPlaying)
46 ,("delete0", testDelete0)
47 ,("delete1", testDelete1)
48 ,("delete2", testDelete2)
49 ,("load", testLoad)
50 ,("move0", testMove0)
51 ,("move1", testMove1)
52 ,("move2", testMove2)
53 ,("rm", testRm)
54 ,("rename", testRename)
55 ,("save", testSave)
56 ,("swap0", testSwap0)
57 ,("swap1", testSwap1)
58 ,("shuffle", testShuffle)
59 ,("playlistInfo0", testPlaylistInfo0)
60 ,("playlistInfo / pos", testPlaylistInfoPos)
61 ,("playlistInfo / id", testPlaylistInfoId)
62 ,("listPlaylistInfo", testListPlaylistInfo)
63 ,("listPlaylist", testListPlaylist)
64 ,("crossfade", testCrossfade)
65 ,("play", testPlay)
66 ,("pause", testPause)
67 ,("stop", testStop)
68 ,("next", testNext)
69 ,("previous", testPrevious)
70 ,("random", testRandom)
71 ,("repeat", testRepeat)
72 ,("setVolume", testSetVolume)
73 ,("volume", testVolume)
74 ,("clearError", testClearError)
75 ,("commands", testCommands)
76 ,("notCommands", testNotCommands)
77 ,("tagTypes", testTagTypes)
78 ,("urlHandlers", testUrlHandlers)
79 ,("ping", testPing)
80 ,("song parsing / incomplete track",
81 testSongParseIncompleteTrack)
82 ,("song parsing / complete track",
83 testSongParseCompleteTrack)
86 test a b c = liftM (showResult b) $ testMPD a b (return Nothing) c
88 test_ a b = test a (Right ()) b
90 showResult :: (Show a) => Response a -> Result a -> String
91 showResult _ Ok = "passed"
92 showResult expectedResult (Failure result mms) =
93 "*** FAILURE ***" ++
94 concatMap (\(x,y) -> "\n expected request: " ++ show x ++
95 "\n actual request: " ++ show y) mms ++
96 "\n expected result: " ++ show expectedResult ++
97 "\n actual result: " ++ show result
99 emptySong = Song { sgArtist = ""
100 , sgAlbum = ""
101 , sgTitle = ""
102 , sgFilePath = ""
103 , sgGenre = ""
104 , sgName = ""
105 , sgComposer = ""
106 , sgPerformer = ""
107 , sgLength = 0
108 , sgDate = 0
109 , sgTrack = (0,0)
110 , sgDisc = (0,0)
111 , sgIndex = Nothing }
114 -- Parser behaviour.
115 -- These tests are meant to expose problems with internal
116 -- parsers.
119 -- Should handle track = 'X'.
120 testSongParseIncompleteTrack =
121 test [("find Artist \"Foo\"", Right "file: dir/Foo-Bar.ogg\n\
122 \Track: 1\n\
123 \OK")]
124 (Right [emptySong { sgTrack = (1,1)
125 , sgFilePath = "dir/Foo-Bar.ogg"
127 (find $ Query Artist "Foo")
129 -- Should handle track = 'X/Y'.
130 testSongParseCompleteTrack =
131 test [("find Artist \"Foo\"", Right "file: dir/Foo-Bar.ogg\n\
132 \Track: 2/12\n\
133 \OK")]
134 (Right [emptySong { sgTrack = (2,12)
135 , sgFilePath = "dir/Foo-Bar.ogg"
137 (find $ Query Artist "Foo")
140 -- Admin commands
143 testEnableOutput = test_ [("enableoutput 1", Right "OK")] (enableOutput 1)
145 testDisableOutput = test_ [("disableoutput 1", Right "OK")] (disableOutput 1)
147 testOutputs =
148 test [("outputs", Right $ unlines ["outputid: 0"
149 ,"outputname: SoundCard0"
150 ,"outputenabled: 1"
151 ,"outputid: 1"
152 ,"outputname: SoundCard1"
153 ,"outputenabled: 0"
154 ,"OK"])]
155 (Right [Device { dOutputID = 0
156 , dOutputName = "SoundCard0"
157 , dOutputEnabled = True }
158 ,Device { dOutputID = 1
159 , dOutputName = "SoundCard1"
160 , dOutputEnabled = False }])
161 outputs
163 testUpdate0 = test_ [("update", Right "updating_db: 1\nOK")] (update [])
165 testUpdate1 =
166 test_ [("update \"foo\"", Right "updating_db: 1\nOK")]
167 (update ["foo"])
169 testUpdateMany =
170 test_ [("command_list_begin\nupdate \"foo\"\nupdate \"bar\"\n\
171 \command_list_end", Right "updating_db: 1\nOK")]
172 (update ["foo","bar"])
175 -- Database commands
178 testFind =
179 test [("find Artist \"Foo\"", Right "file: dir/Foo-Bar.ogg\n\
180 \Time: 60\n\
181 \Artist: Foo\n\
182 \Title: Bar\n\
183 \OK")]
184 (Right [Song { sgArtist = "Foo"
185 , sgAlbum = ""
186 , sgTitle = "Bar"
187 , sgFilePath = "dir/Foo-Bar.ogg"
188 , sgGenre = ""
189 , sgName = ""
190 , sgComposer = ""
191 , sgPerformer = ""
192 , sgLength = 60
193 , sgDate = 0
194 , sgTrack = (0,0)
195 , sgDisc = (0,0)
196 , sgIndex = Nothing
198 (find (Query Artist "Foo"))
200 testListNothing =
201 test [("list Title", Right "Title: Foo\nTitle: Bar\nOK")]
202 (Right ["Foo", "Bar"])
203 (list Title Nothing)
205 testListJust =
206 test [("list Title Artist \"Muzz\"", Right "Title: Foo\nOK")]
207 (Right ["Foo"])
208 (list Title (Just $ Query Artist "Muzz"))
210 testListAll =
211 test [("listall \"\"", Right "directory: FooBand\n\
212 \directory: FooBand/album1\n\
213 \file: FooBand/album1/01 - songA.ogg\n\
214 \file: FooBand/album1/02 - songB.ogg\nOK")]
215 (Right ["FooBand/album1/01 - songA.ogg"
216 ,"FooBand/album1/02 - songB.ogg"])
217 (listAll "")
219 testLsInfo =
220 test [("lsinfo \"\"", Right "directory: Foo\ndirectory: Bar\nOK")]
221 (Right [Left "Bar", Left "Foo"])
222 (lsInfo "")
224 testListAllInfo =
225 test [("listallinfo \"\"", Right "directory: Foo\ndirectory: Bar\nOK")]
226 (Right [Left "Bar", Left "Foo"])
227 (listAllInfo "")
229 testSearch =
230 test [("search Artist \"oo\"", Right "file: dir/Foo-Bar.ogg\n\
231 \Time: 60\n\
232 \Artist: Foo\n\
233 \Title: Bar\n\
234 \OK")]
235 (Right [Song { sgArtist = "Foo"
236 , sgAlbum = ""
237 , sgTitle = "Bar"
238 , sgFilePath = "dir/Foo-Bar.ogg"
239 , sgGenre = ""
240 , sgName = ""
241 , sgComposer = ""
242 , sgPerformer = ""
243 , sgLength = 60
244 , sgDate = 0
245 , sgTrack = (0,0)
246 , sgDisc = (0,0)
247 , sgIndex = Nothing
249 (search (Query Artist "oo"))
251 testCount =
252 test [("count Title \"Foo\"", Right "songs: 1\nplaytime: 60\nOK")]
253 (Right (Count 1 60))
254 (count (Query Title "Foo"))
257 -- Playlist commands
260 testAdd =
261 test [("add \"foo\"", Right "OK"),
262 ("listall \"foo\"", Right "file: Foo\nfile: Bar\nOK")]
263 (Right ["Foo", "Bar"])
264 (add "" "foo")
266 testAdd_ = test_ [("add \"foo\"", Right "OK")] (add_ "" "foo")
268 testAddId =
269 test [("addid \"dir/Foo-Bar.ogg\"", Right "Id: 20\nOK")]
270 (Right 20)
271 (addId "dir/Foo-Bar.ogg")
273 testClear = test_ [("playlistclear \"foo\"", Right "OK")] (clear "foo")
275 testPlChangesPosId_0 =
276 test [("plchangesposid 10", Right "OK")]
277 (Right [])
278 (plChangesPosId 10)
280 testPlChangesPosId_1 =
281 test [("plchangesposid 10", Right "cpos: 0\nId: 20\nOK")]
282 (Right [(Pos 0, ID 20)])
283 (plChangesPosId 10)
285 testPlChangesPosId_Wierd =
286 test [("plchangesposid 10", Right "cpos: foo\nId: bar\nOK")]
287 (Left $ Unexpected "[(\"cpos\",\"foo\"),(\"Id\",\"bar\")]")
288 (plChangesPosId 10)
290 testCurrentSongStopped =
291 test [("status", Right "repeat: 0\n\
292 \random: 0\n\
293 \playlist: 253\n\
294 \playlistlength: 0\n\
295 \xfade: 0\n\
296 \state: stop\nOK")]
297 (Right Nothing)
298 (currentSong)
300 testCurrentSongPlaying =
301 test [("status", Right "volume: 80\n\
302 \repeat: 0\n\
303 \random: 0\n\
304 \playlist: 252\n\
305 \playlistlength: 21\n\
306 \xfade: 0\n\
307 \state: play\n\
308 \song: 20\n\
309 \songid: 238\n\
310 \time: 158:376\n\
311 \bitrate: 192\n\
312 \audio: 44100:16:2\n\
313 \OK")
314 ,("currentsong", Right "file: dir/Foo-Bar.ogg\n\
315 \Time: 60\n\
316 \Artist: Foo\n\
317 \Title: Bar\n\
318 \OK")]
319 (Right . Just $ Song { sgArtist = "Foo"
320 , sgAlbum = ""
321 , sgTitle = "Bar"
322 , sgFilePath = "dir/Foo-Bar.ogg"
323 , sgGenre = ""
324 , sgName = ""
325 , sgComposer = ""
326 , sgPerformer = ""
327 , sgLength = 60
328 , sgDate = 0
329 , sgTrack = (0,0)
330 , sgDisc = (0,0)
331 , sgIndex = Nothing
333 (currentSong)
335 testDelete0 = test_ [("delete 1", Right "OK")] (delete "" (Pos 1))
337 testDelete1 = test_ [("deleteid 1", Right "OK")] (delete "" (ID 1))
339 testDelete2 = test_ [("playlistdelete \"foo\" 1", Right "OK")] (delete "foo" (Pos 1))
341 testLoad = test_ [("load \"foo\"", Right "OK")] (load "foo")
343 testMove0 = test_ [("move 1 2", Right "OK")] (move "" (Pos 1) 2)
345 testMove1 = test_ [("moveid 1 2", Right "OK")] (move "" (ID 1) 2)
347 testMove2 = test_ [("playlistmove \"foo\" 1 2", Right "OK")] (move "foo" (Pos 1) 2)
349 testRm = test_ [("rm \"foo\"", Right "OK")] (rm "foo")
351 testRename = test_ [("rename \"foo\" \"bar\"", Right "OK")] (rename "foo" "bar")
353 testSave = test_ [("save \"foo\"", Right "OK")] (save "foo")
355 testSwap0 = test_ [("swap 1 2", Right "OK")] (swap (Pos 1) (Pos 2))
357 testSwap1 = test_ [("swapid 1 2", Right "OK")] (swap (ID 1) (ID 2))
359 testShuffle = test_ [("shuffle", Right "OK")] shuffle
361 testPlaylistInfo0 = test [("playlistinfo", Right "file: dir/Foo-Bar.ogg\n\
362 \Time: 60\n\
363 \Artist: Foo\n\
364 \Title: Bar\n\
365 \OK")]
366 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
367 , sgLength = 60
368 , sgArtist = "Foo"
369 , sgTitle = "Bar" }])
370 (playlistInfo Nothing)
372 testPlaylistInfoPos = test [("playlistinfo 1", Right "file: dir/Foo-Bar.ogg\n\
373 \Time: 60\n\
374 \Artist: Foo\n\
375 \Title: Bar\n\
376 \OK")]
377 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
378 , sgLength = 60
379 , sgArtist = "Foo"
380 , sgTitle = "Bar" }])
381 (playlistInfo . Just $ Pos 1)
383 testPlaylistInfoId = test [("playlistid 1", Right "file: dir/Foo-Bar.ogg\n\
384 \Time: 60\n\
385 \Artist: Foo\n\
386 \Title: Bar\n\
387 \OK")]
388 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
389 , sgLength = 60
390 , sgArtist = "Foo"
391 , sgTitle = "Bar" }])
392 (playlistInfo . Just $ ID 1)
394 testListPlaylistInfo = test [("listplaylistinfo \"foo\""
395 ,Right "file: dir/Foo-Bar.ogg\n\
396 \Time: 60\n\
397 \Artist: Foo\n\
398 \Title: Bar\n\
399 \OK")]
400 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
401 , sgLength = 60
402 , sgArtist = "Foo"
403 , sgTitle = "Bar" }])
404 (listPlaylistInfo "foo")
406 testListPlaylist = test [("listplaylist \"foo\""
407 ,Right "file: dir/Foo-bar.ogg\n\
408 \file: dir/Quux-quuz.ogg\n\
409 \OK")]
410 (Right ["dir/Foo-bar.ogg", "dir/Quux-quuz.ogg"])
411 (listPlaylist "foo")
414 -- Playback commands
417 testCrossfade = test_ [("crossfade 0", Right "OK")] (crossfade 0)
419 testPlay = test_ [("play", Right "OK")] (play Nothing)
421 testPause = test_ [("pause 0", Right "OK")] (pause False)
423 testStop = test_ [("stop", Right "OK")] stop
425 testNext = test_ [("next", Right "OK")] next
427 testPrevious = test_ [("previous", Right "OK")] previous
429 testRandom = test_ [("random 0", Right "OK")] (random False)
431 testRepeat = test_ [("repeat 0", Right "OK")] (repeat False)
433 testSetVolume = test_ [("setvol 10", Right "OK")] (setVolume 10)
435 testVolume = test_ [("volume 10", Right "OK")] (volume 10)
438 -- Miscellaneous commands
441 testClearError = test_ [("clearerror", Right "OK")] clearError
443 testCommands =
444 test [("commands", Right "command: foo\ncommand: bar")]
445 (Right ["foo", "bar"])
446 commands
448 testNotCommands =
449 test [("notcommands", Right "command: foo\ncommand: bar")]
450 (Right ["foo", "bar"])
451 notCommands
453 testTagTypes =
454 test [("tagtypes", Right "tagtype: foo\ntagtype: bar")]
455 (Right ["foo", "bar"])
456 tagTypes
458 testUrlHandlers =
459 test [("urlhandlers", Right "urlhandler: foo\nurlhandler: bar")]
460 (Right ["foo", "bar"])
461 urlHandlers
463 testPing = test_ [("ping", Right "OK")] ping
466 -- Extensions\/shortcuts