|
| 1 | +{-# LANGUAGE OverloadedStrings #-} |
1 | 2 | module Test.Hspec.Formatters.Codewars |
2 | | - ( |
3 | | - codewars |
4 | | - ) where |
| 3 | + ( |
| 4 | + codewars |
| 5 | + ) where |
5 | 6 |
|
6 | | -import System.IO (Handle) |
7 | | -import Control.Exception (SomeException) |
8 | | -import Control.Monad (unless, join, forM_) |
9 | | -import Text.Printf (printf) |
10 | | -import Data.List (intercalate) |
| 7 | +import Data.Text (pack, unpack, replace) |
11 | 8 |
|
12 | | -import Data.List.Split (splitOn) |
13 | | - |
14 | | -import Test.Hspec.Core.Spec (Progress) |
15 | | -import Test.Hspec.Runner (Path) |
16 | | -import Test.Hspec.Formatters (Formatter (..), FormatM, |
17 | | - FailureRecord (..), FailureReason (..), |
18 | | - getRealTime, |
| 9 | +import Test.Hspec.Formatters (Formatter (..), |
| 10 | + FailureReason (..), |
19 | 11 | formatException, |
20 | | - write, writeLine) |
| 12 | + silent, |
| 13 | + writeLine) |
21 | 14 |
|
22 | 15 | codewars :: Formatter |
23 | | -codewars = Formatter |
24 | | - { headerFormatter = headerFormatter' |
25 | | - , footerFormatter = footerFormatter' |
26 | | - , exampleGroupStarted = exampleGroupStarted' |
27 | | - , exampleGroupDone = exampleGroupDone' |
28 | | - , examplePending = examplePending' |
29 | | - , exampleSucceeded = exampleSucceeded' |
30 | | - , exampleFailed = exampleFailed' |
31 | | - , exampleProgress = exampleProgress' |
32 | | - , failedFormatter = failedFormatter' |
33 | | - } |
34 | | - |
35 | | --- https://hackage.haskell.org/package/hspec-core-2.4.4/docs/Test-Hspec-Core-Formatters.html |
36 | | - |
37 | | -headerFormatter' :: FormatM () |
38 | | -headerFormatter' = return () |
39 | | - |
40 | | -footerFormatter' :: FormatM () |
41 | | -footerFormatter' = return () |
42 | | - |
43 | | --- evaluated before each test group |
44 | | -exampleGroupStarted' :: [String] -> String -> FormatM () |
45 | | -exampleGroupStarted' = \nesting name -> do |
| 16 | +codewars = silent { |
| 17 | + exampleGroupStarted = \_ name -> do |
46 | 18 | writeLine "" |
47 | | - writeLine' $ join $ ["<DESCRIBE::>", name] |
| 19 | + writeLine $ escapeLF $ "<DESCRIBE::>" ++ name |
48 | 20 |
|
49 | | --- evaluated after each test group |
50 | | -exampleGroupDone' :: FormatM () |
51 | | -exampleGroupDone' = writeLine "\n<COMPLETEDIN::>" |
| 21 | +, exampleGroupDone = writeLine "\n<COMPLETEDIN::>" |
52 | 22 |
|
53 | | --- evaluated after each successful example |
54 | | -exampleSucceeded' :: Path -> FormatM () |
55 | | -exampleSucceeded' = \(_, requirement) -> do |
| 23 | +, exampleSucceeded = \(_, name) _ -> do |
56 | 24 | writeLine "" |
57 | | - writeLine' $ join ["<IT::>", requirement] |
| 25 | + writeLine $ escapeLF $ "<IT::>" ++ name |
58 | 26 | writeLine "\n<PASSED::>Test Passed" |
59 | 27 | writeLine "\n<COMPLETEDIN::>" |
60 | 28 |
|
61 | | --- evaluated after each failed example |
62 | | -exampleFailed' :: Path -> Either SomeException FailureReason -> FormatM () |
63 | | -exampleFailed' = \(_, requirement) reason -> do |
| 29 | +, exampleFailed = \(_, name) _ reason -> do |
64 | 30 | writeLine "" |
65 | | - writeLine' $ join ["<IT::>", requirement] |
| 31 | + writeLine $ escapeLF $ "<IT::>" ++ name |
66 | 32 | writeLine "" |
67 | | - formatFailure reason |
| 33 | + writeLine $ escapeLF $ reasonAsString reason |
68 | 34 | writeLine "\n<COMPLETEDIN::>" |
69 | | - |
70 | | --- evaluated after each pending example |
71 | | -examplePending' :: Path -> Maybe String -> FormatM () |
72 | | -examplePending' = \_ _ -> return () |
73 | | - |
74 | | --- Failed test summary |
75 | | --- evaluated after a test run |
76 | | -failedFormatter' :: FormatM () |
77 | | -failedFormatter' = return () |
78 | | - |
79 | | --- used to notify the progress of the currently evaluated example |
80 | | --- Only called when interactive/color mode. |
81 | | -exampleProgress' :: Handle -> Path -> Progress -> IO () |
82 | | -exampleProgress' = \_ _ _ -> return () |
83 | | - |
84 | | -writeLine' :: String -> FormatM () |
85 | | -writeLine' s = writeLine $ intercalate "<:LF:>" $ splitOn "\n" s |
86 | | - |
87 | | -formatFailure :: Either SomeException FailureReason -> FormatM () |
88 | | -formatFailure (Left e) = do |
89 | | - writeLine "" |
90 | | - writeLine' $ ((printf "<ERROR::>%s") . formatException) e |
91 | | -formatFailure (Right NoReason) = do |
92 | | - writeLine "" |
93 | | - writeLine "<FAILED::>Test Failed" |
94 | | -formatFailure (Right (Reason err)) = do |
95 | | - writeLine "" |
96 | | - writeLine' $ (printf "<FAILED::>%s" err) |
97 | | -formatFailure (Right (ExpectedButGot preface expected actual)) = do |
98 | | - writeLine "" |
99 | | - mapM_ writeLine preface |
100 | | - writeLine' $ "<FAILED::>Test Failed\nexpected: " ++ expected ++ "\n but got: " ++ actual |
| 35 | +} |
| 36 | + |
| 37 | +reasonAsString :: FailureReason -> String |
| 38 | +reasonAsString reason = |
| 39 | + case reason of |
| 40 | + NoReason -> "<FAILED::>Test Failed" |
| 41 | + Reason x -> "<FAILED::>" ++ x |
| 42 | + ExpectedButGot Nothing expected got -> |
| 43 | + "<FAILED::>Expected " ++ expected ++ " but got " ++ got |
| 44 | + ExpectedButGot (Just src) expected got -> |
| 45 | + "<FAILED::>" ++ src ++ " expected " ++ expected ++ " but got " ++ got |
| 46 | + Error Nothing err -> |
| 47 | + "<ERROR::>" ++ (formatException err) |
| 48 | + Error (Just s) err -> |
| 49 | + "<ERROR::>" ++ s ++ (formatException err) |
| 50 | + |
| 51 | +escapeLF :: String -> String |
| 52 | +escapeLF = unpack . replace "\n" "<:LF:>" . pack |
0 commit comments