On Tue, Aug 7, 2012 at 12:51 AM, Dean Herington <[email protected]> wrote: > At 4:30 PM -0700 8/5/12, Matthew wrote: >> >> On Sun, Aug 5, 2012 at 12:32 AM, Henk-Jan van Tuyl <[email protected]> >> wrote: >>> >>> On Sun, 05 Aug 2012 03:21:39 +0200, Matthew <[email protected]> >>> wrote: >>> >>>> I've got a function which takes in two chars, describing a playing >>>> card and a suit. An example would be 4C or TH for a 4 of Clubs or a >>>> Ten of Hearts. I need to be able to compare the ranks of a card (e.g. >>>> a King is 13), so a Card is a tuple of rank and suit. The function >>>> which parses a Card is type String -> Maybe Card. >>>> >>>> I'm writing unit tests for this using HUnit, and ideally I'd go with a >>>> table-driven[1] approach, where each test case is a tuple of the input >>>> and the expected output. (Possibly I could expand this to a triple, or >>>> simply a list, to allow for an error message for each test case.) Then >>>> all the test function has to do is run through each case and assert as >>>> necessary. Example: [("TH", Just (Hearts, 10)), ("XH", Nothing)]. >>> >>> >>> >>> A simple solution: >>> >>>> parseCard :: String -> Maybe Card >>>> parseCard string = <your function to test> >>>> test :: Bool >>>> test = all testEqual [("TH", Just (Hearts, 10)), ("XH", Nothing)] >>>> where >>>> testEqual (input, output) = parseCard input == output >>> >>> >>> >>> For a description of 'all', see: >>> >>> >>> http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:all >> >> >> Thanks for the response. The one problem I have with this is that it >> will not be at all obvious which test case (or cases!) failed. >> >> That said, maybe I could do something similar, with a Writer? A passed >> test writes "", but a failed one writes a test-specific failure >> message. Then the test itself uses this string as the assert message. > > > > Let HUnit tell you about the failing test cases. Here's one way to do it. > > > import Test.HUnit > import Data.Char (isDigit) > > data Suit = Spades | Hearts | Diamonds | Clubs > deriving (Show, Read, Eq, Ord) > type Rank = Int -- 2 .. 14 (jack=11, queen=12, king=13, ace=14) > type Card = (Suit, Rank) > > > parseCard :: String -> Maybe Card > parseCard [rankChar, suitChar] = do suit <- suitFrom suitChar; rank <- > rankFrom rankChar; return (suit, rank) > parseCard _ = Nothing > > suitFrom char = lookup char [('S', Spades), ('H', Hearts), ('D', Diamonds), > ('C', Clubs)] > > rankFrom dig | isDigit dig = let v = read [dig] in if v >= 2 then Just v > else Nothing > rankFrom char = lookup char [('T', 10), ('J', 11), ('Q', 12), ('K', 13), > ('A', 14)] > > makeTest :: (String, Maybe Card) -> Test > makeTest (string, result) = string ~: result ~=? parseCard string > > tests = [("TH", Just (Hearts, 10)), ("XH", Nothing)] > > main = (runTestTT . TestList . map makeTest) tests
...it seems so obvious now. This is *exactly* what I was looking for; clearly I was over-thinking this. Thanks, Dean! > > > Dean _______________________________________________ Haskell-Cafe mailing list [email protected] http://www.haskell.org/mailman/listinfo/haskell-cafe
