[gitconv @ N.M.Commands.takeSongInfo: redundant parens]
[libmpd-haskell.git] / tests / Commands.hs
blobf2a35cbef10075f193920374b1bd2257cf2b570a
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 ,("crossfade", testCrossfade)
66 ,("play", testPlay)
67 ,("play / pos", testPlayPos)
68 ,("play / id", testPlayId)
69 ,("pause", testPause)
70 ,("stop", testStop)
71 ,("next", testNext)
72 ,("previous", testPrevious)
73 ,("random", testRandom)
74 ,("repeat", testRepeat)
75 ,("setVolume", testSetVolume)
76 ,("volume", testVolume)
77 ,("clearError", testClearError)
78 ,("commands", testCommands)
79 ,("notCommands", testNotCommands)
80 ,("tagTypes", testTagTypes)
81 ,("urlHandlers", testUrlHandlers)
82 ,("password", testPassword)
83 ,("ping", testPing)
84 ,("song parsing / incomplete track",
85 testSongParseIncompleteTrack)
86 ,("song parsing / complete track",
87 testSongParseCompleteTrack)
90 test a b c = liftM (showResult b) $ testMPD a b (return Nothing) c
92 test_ a b = test a (Right ()) b
94 showResult :: (Show a) => Response a -> Result a -> String
95 showResult _ Ok = "passed"
96 showResult expectedResult (Failure result mms) =
97 "*** FAILURE ***" ++
98 concatMap (\(x,y) -> "\n expected request: " ++ show x ++
99 "\n actual request: " ++ show y) mms ++
100 "\n expected result: " ++ show expectedResult ++
101 "\n actual result: " ++ show result
103 emptySong = Song { sgArtist = ""
104 , sgAlbum = ""
105 , sgTitle = ""
106 , sgFilePath = ""
107 , sgGenre = ""
108 , sgName = ""
109 , sgComposer = ""
110 , sgPerformer = ""
111 , sgLength = 0
112 , sgDate = 0
113 , sgTrack = (0,0)
114 , sgDisc = (0,0)
115 , sgIndex = Nothing }
118 -- Parser behaviour.
119 -- These tests are meant to expose problems with internal
120 -- parsers.
123 -- Should handle track = 'X'.
124 testSongParseIncompleteTrack =
125 test [("find Artist \"Foo\"", Right "file: dir/Foo-Bar.ogg\n\
126 \Track: 1\n\
127 \OK")]
128 (Right [emptySong { sgTrack = (1,1)
129 , sgFilePath = "dir/Foo-Bar.ogg"
131 (find $ Query Artist "Foo")
133 -- Should handle track = 'X/Y'.
134 testSongParseCompleteTrack =
135 test [("find Artist \"Foo\"", Right "file: dir/Foo-Bar.ogg\n\
136 \Track: 2/12\n\
137 \OK")]
138 (Right [emptySong { sgTrack = (2,12)
139 , sgFilePath = "dir/Foo-Bar.ogg"
141 (find $ Query Artist "Foo")
144 -- Admin commands
147 testEnableOutput = test_ [("enableoutput 1", Right "OK")] (enableOutput 1)
149 testDisableOutput = test_ [("disableoutput 1", Right "OK")] (disableOutput 1)
151 testOutputs =
152 test [("outputs", Right $ unlines ["outputid: 0"
153 ,"outputname: SoundCard0"
154 ,"outputenabled: 1"
155 ,"outputid: 1"
156 ,"outputname: SoundCard1"
157 ,"outputenabled: 0"
158 ,"OK"])]
159 (Right [Device { dOutputID = 0
160 , dOutputName = "SoundCard0"
161 , dOutputEnabled = True }
162 ,Device { dOutputID = 1
163 , dOutputName = "SoundCard1"
164 , dOutputEnabled = False }])
165 outputs
167 testUpdate0 = test_ [("update", Right "updating_db: 1\nOK")] (update [])
169 testUpdate1 =
170 test_ [("update \"foo\"", Right "updating_db: 1\nOK")]
171 (update ["foo"])
173 testUpdateMany =
174 test_ [("command_list_begin\nupdate \"foo\"\nupdate \"bar\"\n\
175 \command_list_end", Right "updating_db: 1\nOK")]
176 (update ["foo","bar"])
179 -- Database commands
182 testFind =
183 test [("find Artist \"Foo\"", Right "file: dir/Foo-Bar.ogg\n\
184 \Time: 60\n\
185 \Artist: Foo\n\
186 \Title: Bar\n\
187 \OK")]
188 (Right [Song { sgArtist = "Foo"
189 , sgAlbum = ""
190 , sgTitle = "Bar"
191 , sgFilePath = "dir/Foo-Bar.ogg"
192 , sgGenre = ""
193 , sgName = ""
194 , sgComposer = ""
195 , sgPerformer = ""
196 , sgLength = 60
197 , sgDate = 0
198 , sgTrack = (0,0)
199 , sgDisc = (0,0)
200 , sgIndex = Nothing
202 (find (Query Artist "Foo"))
204 testListNothing =
205 test [("list Title", Right "Title: Foo\nTitle: Bar\nOK")]
206 (Right ["Foo", "Bar"])
207 (list Title Nothing)
209 testListJust =
210 test [("list Title Artist \"Muzz\"", Right "Title: Foo\nOK")]
211 (Right ["Foo"])
212 (list Title (Just $ Query Artist "Muzz"))
214 testListAll =
215 test [("listall \"\"", Right "directory: FooBand\n\
216 \directory: FooBand/album1\n\
217 \file: FooBand/album1/01 - songA.ogg\n\
218 \file: FooBand/album1/02 - songB.ogg\nOK")]
219 (Right ["FooBand/album1/01 - songA.ogg"
220 ,"FooBand/album1/02 - songB.ogg"])
221 (listAll "")
223 testLsInfo =
224 test [("lsinfo \"\"", Right "directory: Foo\ndirectory: Bar\nOK")]
225 (Right [Left "Bar", Left "Foo"])
226 (lsInfo "")
228 testListAllInfo =
229 test [("listallinfo \"\"", Right "directory: Foo\ndirectory: Bar\nOK")]
230 (Right [Left "Bar", Left "Foo"])
231 (listAllInfo "")
233 testSearch =
234 test [("search Artist \"oo\"", Right "file: dir/Foo-Bar.ogg\n\
235 \Time: 60\n\
236 \Artist: Foo\n\
237 \Title: Bar\n\
238 \OK")]
239 (Right [Song { sgArtist = "Foo"
240 , sgAlbum = ""
241 , sgTitle = "Bar"
242 , sgFilePath = "dir/Foo-Bar.ogg"
243 , sgGenre = ""
244 , sgName = ""
245 , sgComposer = ""
246 , sgPerformer = ""
247 , sgLength = 60
248 , sgDate = 0
249 , sgTrack = (0,0)
250 , sgDisc = (0,0)
251 , sgIndex = Nothing
253 (search (Query Artist "oo"))
255 testCount =
256 test [("count Title \"Foo\"", Right "songs: 1\nplaytime: 60\nOK")]
257 (Right (Count 1 60))
258 (count (Query Title "Foo"))
261 -- Playlist commands
264 testAdd =
265 test [("add \"foo\"", Right "OK"),
266 ("listall \"foo\"", Right "file: Foo\nfile: Bar\nOK")]
267 (Right ["Foo", "Bar"])
268 (add "" "foo")
270 testAdd_ = test_ [("add \"foo\"", Right "OK")] (add_ "" "foo")
272 testAdd_pl = test_ [("playlistadd \"foo\" \"bar\"", Right "OK")]
273 (add_ "foo" "bar")
275 testAddId =
276 test [("addid \"dir/Foo-Bar.ogg\"", Right "Id: 20\nOK")]
277 (Right 20)
278 (addId "dir/Foo-Bar.ogg")
280 testClear = test_ [("playlistclear \"foo\"", Right "OK")] (clear "foo")
282 testPlChangesPosId_0 =
283 test [("plchangesposid 10", Right "OK")]
284 (Right [])
285 (plChangesPosId 10)
287 testPlChangesPosId_1 =
288 test [("plchangesposid 10", Right "cpos: 0\nId: 20\nOK")]
289 (Right [(Pos 0, ID 20)])
290 (plChangesPosId 10)
292 testPlChangesPosId_Wierd =
293 test [("plchangesposid 10", Right "cpos: foo\nId: bar\nOK")]
294 (Left $ Unexpected "[(\"cpos\",\"foo\"),(\"Id\",\"bar\")]")
295 (plChangesPosId 10)
297 testCurrentSongStopped =
298 test [("status", Right "repeat: 0\n\
299 \random: 0\n\
300 \playlist: 253\n\
301 \playlistlength: 0\n\
302 \xfade: 0\n\
303 \state: stop\nOK")]
304 (Right Nothing)
305 (currentSong)
307 testCurrentSongPlaying =
308 test [("status", Right "volume: 80\n\
309 \repeat: 0\n\
310 \random: 0\n\
311 \playlist: 252\n\
312 \playlistlength: 21\n\
313 \xfade: 0\n\
314 \state: play\n\
315 \song: 20\n\
316 \songid: 238\n\
317 \time: 158:376\n\
318 \bitrate: 192\n\
319 \audio: 44100:16:2\n\
320 \OK")
321 ,("currentsong", Right "file: dir/Foo-Bar.ogg\n\
322 \Time: 60\n\
323 \Artist: Foo\n\
324 \Title: Bar\n\
325 \OK")]
326 (Right . Just $ Song { sgArtist = "Foo"
327 , sgAlbum = ""
328 , sgTitle = "Bar"
329 , sgFilePath = "dir/Foo-Bar.ogg"
330 , sgGenre = ""
331 , sgName = ""
332 , sgComposer = ""
333 , sgPerformer = ""
334 , sgLength = 60
335 , sgDate = 0
336 , sgTrack = (0,0)
337 , sgDisc = (0,0)
338 , sgIndex = Nothing
340 (currentSong)
342 testDelete0 = test_ [("delete 1", Right "OK")] (delete "" (Pos 1))
344 testDelete1 = test_ [("deleteid 1", Right "OK")] (delete "" (ID 1))
346 testDelete2 = test_ [("playlistdelete \"foo\" 1", Right "OK")] (delete "foo" (Pos 1))
348 testLoad = test_ [("load \"foo\"", Right "OK")] (load "foo")
350 testMove0 = test_ [("move 1 2", Right "OK")] (move "" (Pos 1) 2)
352 testMove1 = test_ [("moveid 1 2", Right "OK")] (move "" (ID 1) 2)
354 testMove2 = test_ [("playlistmove \"foo\" 1 2", Right "OK")] (move "foo" (Pos 1) 2)
356 testRm = test_ [("rm \"foo\"", Right "OK")] (rm "foo")
358 testRename = test_ [("rename \"foo\" \"bar\"", Right "OK")] (rename "foo" "bar")
360 testSave = test_ [("save \"foo\"", Right "OK")] (save "foo")
362 testSwap0 = test_ [("swap 1 2", Right "OK")] (swap (Pos 1) (Pos 2))
364 testSwap1 = test_ [("swapid 1 2", Right "OK")] (swap (ID 1) (ID 2))
366 testShuffle = test_ [("shuffle", Right "OK")] shuffle
368 testPlaylistInfo0 = test [("playlistinfo", Right "file: dir/Foo-Bar.ogg\n\
369 \Time: 60\n\
370 \Artist: Foo\n\
371 \Title: Bar\n\
372 \OK")]
373 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
374 , sgLength = 60
375 , sgArtist = "Foo"
376 , sgTitle = "Bar" }])
377 (playlistInfo Nothing)
379 testPlaylistInfoPos = test [("playlistinfo 1", Right "file: dir/Foo-Bar.ogg\n\
380 \Time: 60\n\
381 \Artist: Foo\n\
382 \Title: Bar\n\
383 \OK")]
384 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
385 , sgLength = 60
386 , sgArtist = "Foo"
387 , sgTitle = "Bar" }])
388 (playlistInfo . Just $ Pos 1)
390 testPlaylistInfoId = test [("playlistid 1", Right "file: dir/Foo-Bar.ogg\n\
391 \Time: 60\n\
392 \Artist: Foo\n\
393 \Title: Bar\n\
394 \OK")]
395 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
396 , sgLength = 60
397 , sgArtist = "Foo"
398 , sgTitle = "Bar" }])
399 (playlistInfo . Just $ ID 1)
401 testListPlaylistInfo = test [("listplaylistinfo \"foo\""
402 ,Right "file: dir/Foo-Bar.ogg\n\
403 \Time: 60\n\
404 \Artist: Foo\n\
405 \Title: Bar\n\
406 \OK")]
407 (Right [emptySong { sgFilePath = "dir/Foo-Bar.ogg"
408 , sgLength = 60
409 , sgArtist = "Foo"
410 , sgTitle = "Bar" }])
411 (listPlaylistInfo "foo")
413 testListPlaylist = test [("listplaylist \"foo\""
414 ,Right "file: dir/Foo-bar.ogg\n\
415 \file: dir/Quux-quuz.ogg\n\
416 \OK")]
417 (Right ["dir/Foo-bar.ogg", "dir/Quux-quuz.ogg"])
418 (listPlaylist "foo")
421 -- Playback commands
424 testCrossfade = test_ [("crossfade 0", Right "OK")] (crossfade 0)
426 testPlay = test_ [("play", Right "OK")] (play Nothing)
428 testPlayPos = test_ [("play 1", Right "OK")] (play . Just $ Pos 1)
430 testPlayId = test_ [("playid 1", Right "OK")] (play . Just $ ID 1)
432 testPause = test_ [("pause 0", Right "OK")] (pause False)
434 testStop = test_ [("stop", Right "OK")] stop
436 testNext = test_ [("next", Right "OK")] next
438 testPrevious = test_ [("previous", Right "OK")] previous
440 testRandom = test_ [("random 0", Right "OK")] (random False)
442 testRepeat = test_ [("repeat 0", Right "OK")] (repeat False)
444 testSetVolume = test_ [("setvol 10", Right "OK")] (setVolume 10)
446 testVolume = test_ [("volume 10", Right "OK")] (volume 10)
449 -- Miscellaneous commands
452 testClearError = test_ [("clearerror", Right "OK")] clearError
454 testCommands =
455 test [("commands", Right "command: foo\ncommand: bar")]
456 (Right ["foo", "bar"])
457 commands
459 testNotCommands =
460 test [("notcommands", Right "command: foo\ncommand: bar")]
461 (Right ["foo", "bar"])
462 notCommands
464 testTagTypes =
465 test [("tagtypes", Right "tagtype: foo\ntagtype: bar")]
466 (Right ["foo", "bar"])
467 tagTypes
469 testUrlHandlers =
470 test [("urlhandlers", Right "urlhandler: foo\nurlhandler: bar")]
471 (Right ["foo", "bar"])
472 urlHandlers
474 testPassword = test_ [("password foo", Right "OK")] (password "foo")
476 testPing = test_ [("ping", Right "OK")] ping
479 -- Extensions\/shortcuts