
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)]. The problem, of course, is that I've no clue how to make this work. I still don't *quite* grok do notation well enough to understand how I can bind a monadic value (in this case a Maybe Card), pattern match on such as the Integer in there, and then assertEqual. I suspect I'm just thinking about this all wrong. Any suggestions? Thanks again! [1]: http://code.google.com/p/go-wiki/wiki/TableDrivenTests

On Sun, 05 Aug 2012 03:21:39 +0200, Matthew
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.htm... Regards, Henk-Jan van Tuyl -- http://Van.Tuyl.eu/ http://members.chello.nl/hjgtuyl/tourdemonad.html Haskell programming --

On Sun, Aug 5, 2012 at 12:32 AM, Henk-Jan van Tuyl
On Sun, 05 Aug 2012 03:21:39 +0200, Matthew
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.htm...
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.
Regards, Henk-Jan van Tuyl
-- http://Van.Tuyl.eu/ http://members.chello.nl/hjgtuyl/tourdemonad.html Haskell programming --

At 4:30 PM -0700 8/5/12, Matthew wrote:
On Sun, Aug 5, 2012 at 12:32 AM, Henk-Jan van Tuyl
wrote: On Sun, 05 Aug 2012 03:21:39 +0200, Matthew
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.htm...
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 Dean
participants (3)
-
Dean Herington
-
Henk-Jan van Tuyl
-
Matthew