Skip to content

Commit c2efafc

Browse files
hobovskykazk
andauthored
Update to formatters V2 and add durations (#6)
Co-authored-by: kazk <[email protected]>
1 parent cd57285 commit c2efafc

File tree

5 files changed

+108
-31
lines changed

5 files changed

+108
-31
lines changed

hspec-formatters-codewars.cabal

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ test-suite hspec-formatters-codewars-test
4545
test
4646
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
4747
build-depends:
48-
base >=4.7 && <5
48+
QuickCheck
49+
, base >=4.7 && <5
4950
, hspec >=2.8
5051
, hspec-core >=2.8
5152
, hspec-formatters-codewars

package.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ tests:
4848
- hspec >= 2.8
4949
- hspec-core >= 2.8
5050
- hspec-formatters-codewars
51+
- QuickCheck
5152
verbatim:
5253
build-tool-depends:
5354
hspec-discover:hspec-discover
Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,81 @@
11
{-# LANGUAGE OverloadedStrings #-}
22

3-
module Test.Hspec.Formatters.Codewars (codewars) where
3+
module Test.Hspec.Formatters.Codewars (codewars, escapeLF) where
44

55
import Data.Text (pack, replace, unpack)
6+
import Text.Printf (printf)
7+
import Data.IORef
8+
import Control.Monad.IO.Class
9+
import Test.Hspec.Core.Util (Path)
610

7-
import Test.Hspec.Core.Formatters.V1 (
11+
import Test.Hspec.Core.Formatters.V2 (
812
FailureReason (..),
9-
Formatter (..),
13+
Formatter (..),
14+
Item (..),
15+
Seconds (..),
16+
Result (..),
1017
formatException,
1118
silent,
1219
writeLine,
20+
getRealTime
1321
)
1422

15-
codewars :: Formatter
16-
codewars =
17-
silent
18-
{ exampleGroupStarted = \_ name -> do
23+
getName :: Path -> String
24+
getName (_, req) = escapeLF req
25+
26+
codewars :: IO Formatter
27+
codewars = do
28+
times <- newIORef ([ ]::[Seconds])
29+
pure $ silent
30+
{
31+
formatterGroupStarted = \path -> do
32+
writeLine ""
33+
startedOn <- getRealTime
34+
liftIO $ modifyIORef times (startedOn : )
35+
writeLine $ "<DESCRIBE::>" ++ (getName path)
36+
,formatterGroupDone = \_ -> do
1937
writeLine ""
20-
writeLine $ escapeLF $ "<DESCRIBE::>" ++ name
21-
, exampleGroupDone = writeLine "\n<COMPLETEDIN::>"
22-
, exampleSucceeded = \(_, name) _ -> do
38+
ts <- liftIO $ readIORef times
39+
now <- getRealTime
40+
let startedOn = head ts
41+
let duration = now - startedOn
42+
writeLine $ "<COMPLETEDIN::>" ++ (formatToMillis $ duration)
43+
liftIO $ modifyIORef times tail
44+
,formatterItemStarted = \path -> do
2345
writeLine ""
24-
writeLine $ escapeLF $ "<IT::>" ++ name
25-
writeLine "\n<PASSED::>Test Passed"
26-
writeLine "\n<COMPLETEDIN::>"
27-
, exampleFailed = \(_, name) _ reason -> do
46+
writeLine $ "<IT::>" ++ (getName path)
47+
,formatterItemDone = \_ item -> do
2848
writeLine ""
29-
writeLine $ escapeLF $ "<IT::>" ++ name
49+
writeLine $ reportItem item
3050
writeLine ""
31-
writeLine $ escapeLF $ reasonAsString reason
32-
writeLine "\n<COMPLETEDIN::>"
51+
writeLine $ "<COMPLETEDIN::>" ++ (formatToMillis $ itemDuration item)
3352
}
3453

54+
reportItem :: Item -> String
55+
reportItem item =
56+
case itemResult item of
57+
Success -> "<PASSED::>Test Passed"
58+
Failure _ reason -> reasonAsString reason
59+
Pending _ Nothing -> "<FAILED::>Test pending: no reason given"
60+
Pending _ (Just msg) -> "<FAILED::>Test pending: " ++ (escapeLF msg)
61+
3562
reasonAsString :: FailureReason -> String
3663
reasonAsString reason =
3764
case reason of
3865
NoReason -> "<FAILED::>Test Failed"
39-
Reason x -> "<FAILED::>" ++ x
66+
Reason x -> "<FAILED::>" ++ (escapeLF x)
4067
ExpectedButGot Nothing expected got ->
41-
"<FAILED::>Expected " ++ expected ++ " but got " ++ got
68+
"<FAILED::>expected: " ++ (escapeLF expected) ++ "<:LF:> but got: " ++ (escapeLF got)
4269
ExpectedButGot (Just src) expected got ->
43-
"<FAILED::>" ++ src ++ " expected " ++ expected ++ " but got " ++ got
70+
"<FAILED::>" ++ (escapeLF src) ++ "<:LF:>expected: " ++ (escapeLF expected) ++ "<:LF:> but got: " ++ (escapeLF got)
4471
Error Nothing err ->
45-
"<ERROR::>" ++ formatException err
72+
"<ERROR::>uncaught exception: " ++ (escapeLF $ formatException err)
4673
Error (Just s) err ->
47-
"<ERROR::>" ++ s ++ formatException err
74+
"<ERROR::>" ++ (escapeLF s) ++ "<:LF:>" ++ (escapeLF $ formatException err)
75+
76+
77+
formatToMillis :: Seconds -> String
78+
formatToMillis (Seconds s) = printf "%.3f" (s * 1000)
4879

4980
escapeLF :: String -> String
5081
escapeLF = unpack . replace "\n" "<:LF:>" . pack

test/ExampleSpec.hs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,45 @@
11
module ExampleSpec where
22

33
import Test.Hspec
4+
import Test.QuickCheck
45

56
spec :: Spec
67
spec = describe "ExampleSpec" $ do
7-
it "can parse integers" $ do
8-
read "10" `shouldBe` (10 :: Int)
9-
10-
it "can parse floating-point numbers" $ do
11-
read "2.5" `shouldBe` (2.5 :: Float)
8+
describe "Passing tests" $ do
9+
it "can parse integers" $ do
10+
read "10" `shouldBe` (10 :: Int)
11+
it "can parse floating-point numbers" $ do
12+
read "2.5" `shouldBe` (2.5 :: Float)
13+
describe "Failing tests" $ do
14+
it "can parse integers and fail" $ do
15+
read "10" `shouldBe` (11 :: Int)
16+
it "can parse floating-point numbers and fail" $ do
17+
read "2.5" `shouldBe` (2.6 :: Float)
18+
it "explicitly trigerred error" $ do
19+
error "This test fails with an error"
20+
read "10" `shouldBe` (10 :: Int)
21+
describe "Crashing tests" $ do
22+
it "can parse integers and crash" $ do
23+
read (last $ tail $ [ "10" ]) `shouldBe` (11 :: Int)
24+
it "can parse floating-point numbers and crash" $ do
25+
read (last $ tail $ [ "2.5" ]) `shouldBe` (2.6 :: Float)
26+
describe "Pending tests" $ do
27+
it "not implemented" $ do
28+
pending
29+
it "not implemented, with a message" $ do
30+
pendingWith "Not implemented yet"
31+
describe "Can present\nmultiline titles\nof groups" $ do
32+
it "Can present\nmultiline titles\nof items" $ do
33+
read "10" `shouldBe` (10 :: Int)
34+
it "Can present multiline assertions" $ do
35+
(show 10) `shouldBe` "10, but\nbroken into\nmultiple lines"
36+
describe "QuickCheck tests" $ do
37+
it "passes for random ints" $ do
38+
property $ \ n -> do
39+
((read (show n))::Int) `shouldBe` (n :: Int)
40+
it "fails for random ints" $ do
41+
property $ \ n -> do
42+
((read (show n))::Int) `shouldBe` ((if n < 50 then n else n + 1) :: Int)
43+
-- describe "Can crash whole test suite" $ do
44+
-- it ("can parse item title " ++ (show $ ((read "cant parse this")::Int)) ++ " and crash") $ do
45+
-- read "2.5" `shouldBe` (2.5 :: Float)

test/Main.hs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
module Main (main) where
22

3+
import System.Exit
4+
35
import Test.Hspec.Runner
4-
import Test.Hspec.Formatters.Codewars (codewars)
5-
import Test.Hspec.Core.Formatters.V1 (formatterToFormat)
6+
import Test.Hspec.Formatters.Codewars (codewars, escapeLF)
7+
import Test.Hspec.Core.Formatters.V2 (formatterToFormat, formatException)
8+
import Test.Hspec.Core.Util (safeTry)
69

710
import qualified Spec
811

912
main :: IO ()
10-
main = hspecWith defaultConfig {configFormat = Just $ formatterToFormat codewars} Spec.spec
13+
main = do
14+
formatter <- codewars
15+
summary <- safeTry $ runSpec Spec.spec defaultConfig {configFormat = Just $ formatterToFormat formatter}
16+
case summary of
17+
Left ex -> do
18+
putStrLn $ "\n<ERROR::>Test suite crashed<:LF:>" ++ (escapeLF $ formatException ex)
19+
exitFailure
20+
Right s -> evaluateSummary s

0 commit comments

Comments
 (0)