Skip to content

Commit 56237d1

Browse files
authored
Merge pull request #224 from rbasso/hspec-anagram
anagram: Rewrite to use hspec with fail-fast.
2 parents bab4047 + b9504c7 commit 56237d1

File tree

2 files changed

+137
-37
lines changed

2 files changed

+137
-37
lines changed

exercises/anagram/package.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ tests:
1616
source-dirs: test
1717
dependencies:
1818
- anagram
19-
- HUnit
19+
- hspec

exercises/anagram/test/Tests.hs

Lines changed: 136 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,140 @@
1-
import Test.HUnit (Assertion, (@=?), runTestTT, Test(..), Counts(..))
2-
import System.Exit (ExitCode(..), exitWith)
3-
import Anagram (anagramsFor)
1+
{-# LANGUAGE RecordWildCards #-}
42

5-
exitProperly :: IO Counts -> IO ()
6-
exitProperly m = do
7-
counts <- m
8-
exitWith $ if failures counts /= 0 || errors counts /= 0 then ExitFailure 1 else ExitSuccess
3+
import Data.Foldable (for_)
4+
import Test.Hspec (Spec, describe, it, shouldBe)
5+
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)
96

10-
testCase :: String -> Assertion -> Test
11-
testCase label assertion = TestLabel label (TestCase assertion)
7+
import Anagram (anagramsFor)
128

139
main :: IO ()
14-
main = exitProperly (runTestTT (TestList anagramTests))
15-
16-
anagramTests :: [Test]
17-
anagramTests =
18-
[ testCase "no matches" $
19-
[] @=? anagramsFor "diaper" ["hello", "world", "zombies", "pants"]
20-
, testCase "detect simple anagram" $
21-
["tan"] @=? anagramsFor "ant" ["tan", "stand", "at"]
22-
, testCase "does not confuse different duplicates" $
23-
[] @=? anagramsFor "galea" ["eagle"]
24-
, testCase "eliminate anagram subsets" $
25-
[] @=? anagramsFor "good" ["dog", "goody"]
26-
, testCase "detect anagram" $
27-
["inlets"] @=? anagramsFor "listen" ["enlists", "google",
28-
"inlets", "banana"]
29-
, testCase "multiple anagrams" $
30-
["gallery", "regally", "largely"] @=?
31-
anagramsFor "allergy" ["gallery", "ballerina", "regally", "clergy",
32-
"largely", "leading"]
33-
, testCase "case insensitive anagrams" $
34-
["Carthorse"] @=?
35-
anagramsFor "Orchestra" ["cashregister", "Carthorse", "radishes"]
36-
, testCase "does not detect a word as its own anagram" $
37-
[] @=? anagramsFor "banana" ["banana"]
38-
, testCase "does not detect a word as its own anagram (case insensitive)" $
39-
[] @=? anagramsFor "Banana" ["baNana"]
40-
]
10+
main = hspecWith defaultConfig {configFastFail = True} specs
11+
12+
specs :: Spec
13+
specs = describe "anagram" $
14+
describe "anagramsFor" $ for_ cases test
15+
where
16+
17+
test Case{..} = it description $ expression `shouldBe` expected
18+
where
19+
expression = anagramsFor subject candidates
20+
21+
-- Test cases adapted from `exercism/x-common/anagrams.json` on 2016-07-25.
22+
23+
data Case = Case { description :: String
24+
, subject :: String
25+
, candidates :: [String]
26+
, expected :: [String]
27+
}
28+
29+
cases :: [Case]
30+
cases = [ Case { description = "no matches"
31+
, subject = "diaper"
32+
, candidates = [ "hello", "world", "zombies", "pants"]
33+
, expected = []
34+
}
35+
, Case { description = "detects simple anagram"
36+
, subject = "ant"
37+
, candidates = ["tan", "stand", "at"]
38+
, expected = ["tan"]
39+
}
40+
, Case { description = "does not detect false positives"
41+
, subject = "galea"
42+
, candidates = ["eagle"]
43+
, expected = []
44+
}
45+
, Case { description = "detects multiple anagrams"
46+
, subject = "master"
47+
, candidates = ["stream", "pigeon", "maters"]
48+
, expected = ["stream", "maters"]
49+
}
50+
, Case { description = "does not detect anagram subsets"
51+
, subject = "good"
52+
, candidates = ["dog", "goody"]
53+
, expected = []
54+
}
55+
, Case { description = "detects anagram"
56+
, subject = "listen"
57+
, candidates = ["enlists", "google", "inlets", "banana"]
58+
, expected = ["inlets"]
59+
}
60+
, Case { description = "detects multiple anagrams"
61+
, subject = "allergy"
62+
, candidates = ["gallery", "ballerina", "regally", "clergy", "largely", "leading"]
63+
, expected = ["gallery", "regally", "largely"]
64+
}
65+
, Case { description = "does not detect indentical words"
66+
, subject = "corn"
67+
, candidates = ["corn", "dark", "Corn", "rank", "CORN", "cron", "park"]
68+
, expected = ["cron"]
69+
}
70+
, Case { description = "does not detect non-anagrams with identical checksum"
71+
, subject = "mass"
72+
, candidates = ["last"]
73+
, expected = []
74+
}
75+
, Case { description = "detects anagrams case-insensitively"
76+
, subject = "Orchestra"
77+
, candidates = ["cashregister", "Carthorse", "radishes"]
78+
, expected = ["Carthorse"]
79+
}
80+
, Case { description = "detects anagrams using case-insensitive subject"
81+
, subject = "Orchestra"
82+
, candidates = ["cashregister", "carthorse", "radishes"]
83+
, expected = ["carthorse"]
84+
}
85+
, Case { description = "detects anagrams using case-insensitve possible matches"
86+
, subject = "orchestra"
87+
, candidates = ["cashregister", "Carthorse", "radishes"]
88+
, expected = ["Carthorse"]
89+
}
90+
, Case { description = "does not detect a word as its own anagram"
91+
, subject = "banana"
92+
, candidates = ["Banana"]
93+
, expected = []
94+
}
95+
, Case { description = "does not detect a anagram if the original word is repeated"
96+
, subject = "go"
97+
, candidates = ["go Go GO"]
98+
, expected = []
99+
}
100+
, Case { description = "anagrams must use all letters exactly once"
101+
, subject = "tapper"
102+
, candidates = ["patter"]
103+
, expected = []
104+
}
105+
, Case { description = "eliminates anagrams with the same checksum"
106+
, subject = "mass"
107+
, candidates = ["last"]
108+
, expected = []
109+
}
110+
, Case { description = "detects unicode anagrams"
111+
, subject = "ΑΒΓ"
112+
, candidates = ["ΒΓΑ", "ΒΓΔ", "γβα"]
113+
, expected = ["ΒΓΑ", "γβα"]
114+
}
115+
, Case { description = "eliminates misleading unicode anagrams"
116+
, subject = "ΑΒΓ"
117+
, candidates = ["ABΓ"]
118+
, expected = []
119+
}
120+
, Case { description = "capital word is not own anagram"
121+
, subject = "BANANA"
122+
, candidates = ["Banana"]
123+
, expected = []
124+
}
125+
, Case { description = "anagrams must use all letters exactly once"
126+
, subject = "patter"
127+
, candidates = ["tapper"]
128+
, expected = []
129+
}
130+
, Case { description = "accepts string arguments"
131+
, subject = "ant"
132+
, candidates = ["stand", "tan", "at"]
133+
, expected = ["tan"]
134+
}
135+
, Case { description = "accepts single string argument"
136+
, subject = "ant"
137+
, candidates = ["tan"]
138+
, expected = ["tan"]
139+
}
140+
]

0 commit comments

Comments
 (0)