hmp3-ng-2.18.1: test/LexerSpec.hs
module LexerSpec (tests) where
import Test.Tasty
import Test.Tasty.HUnit
import qualified Data.ByteString.Char8 as P
import Lexer (mpgParser)
import Syntax
-- These exercise the helpers doX, 'trim', and 'normalise'.
tests :: TestTree
tests = testGroup "Lexer.mpgParser"
[ testGroup "status (@P)"
[ tc "@P 0" $ Right (S Stopped)
, tc "@P 1" $ Right (S Paused)
, tc "@P 2" $ Right (S Playing)
, tc "@P 3" $ Left Nothing -- end-of-song marker: ignored (no double play)
, tc "@P 9" $ Left Nothing -- unknown code
, tc "@P " $ Left Nothing -- no payload
]
, testGroup "frame (@F)"
[ tc "@F 123 456 12.34 56.78" $ Right (R (Frame 123 456 12.34 56.78))
, tc "@F 0 0 0.00 -1.00" $ Right (R (Frame 0 0 0.00 0)) -- timeLeft clamped
, tc "@F 1 2 3.00" $ Left Nothing -- too few fields
, tc "@F a b c d" $ Left Nothing -- non-numeric
]
, testGroup "stream info (@S)"
[ tc "@S 1.0 1 44100 stereo 0 0 2 0 0 0 128 0"
$ Right (I (Info "mpeg 1.0 128kbit/s 44kHz"))
, tc "@S 1.0 1 44100" $ Left Nothing -- too few fields
]
, testGroup "id3 (@I)" (let s = "n\195\182rmalise" in
[ tcId3 ["Title"]
$ Right (F (Id3 "Title" "" "" "Title"))
, tcId3 ["Title", "Artist"]
$ Right (F (Id3 "Title" "Artist" "" "Artist : Title"))
, tcId3 [" Title", " Artist"]
$ Right (F (Id3 "Title" "Artist" "" "Artist : Title"))
, tcId3 ["Title", "Artist", "Album"]
$ Right (F (Id3 "Title" "Artist" "Album" "Artist : Album : Title"))
, tcId3 ["", "Artist"] $ Left Nothing -- blank title: skipped
, tc "@I song.mp3" $ Left Nothing -- non-ID3 @I: don't overwrite
, tc "@I {" $ Left Nothing -- grouping marker: ignored
, tcId3 ["nörmalise"] $ Right (F (Id3 s "" "" s))
, tcId3 [s] $ Right (F (Id3 s "" "" s))
])
, testGroup "tagline, errors, junk"
[ tc "@R a tagline" $ Right (T Tag)
, tc "@E some failure" $ Left (Just "some failure")
, tc "garbage" $ Left Nothing -- no @ prefix
, tc "@F" $ Left Nothing -- no space after code
, tc "@" $ Left Nothing
, tc "" $ Left Nothing
]
]
where
tc line = tc' (show line) line
tc' tag line expected = testCase tag $ mpgParser line @?= expected
tcId3 fields = tc' (show fields) (id3 fields)
-- | Build an "@I ID3:" line from fixed-width 30-char fields, as mpg123 emits.
id3 :: [P.ByteString] -> P.ByteString
id3 fields = "@I ID3:" <> mconcat [ P.take 30 (f <> P.replicate 30 ' ') | f <- fields ]