{-# LANGUAGE NamedFieldPuns #-}
{-# OPTIONS_GHC -Wno-missing-export-lists #-}
module Test.MockCat.Internal.Message where
import Data.List (intercalate, maximumBy, elemIndex)
import Data.Ord (comparing)
import Data.Char (isLower)
import Data.Text (pack, replace, unpack)
import Test.MockCat.Internal.Types
message :: Show a => Maybe MockName -> a -> a -> String
message :: forall a. Show a => Maybe String -> a -> a -> String
message Maybe String
name a
expected a
actual =
let expectedStr :: String
expectedStr = String -> String
formatStr (a -> String
forall a. Show a => a -> String
show a
expected)
actualStr :: String
actualStr = String -> String
formatStr (a -> String
forall a. Show a => a -> String
show a
actual)
diffLine :: String
diffLine = String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String -> String
diffPointer String
expectedStr String
actualStr
mainMessage :: String
mainMessage = String
"function" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Maybe String -> String
mockNameLabel Maybe String
name String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" was not called with the expected arguments."
in case String -> String -> [Difference]
structuralDiff String
expectedStr String
actualStr of
[] ->
String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n"
[ String
mainMessage,
String
" expected: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
expectedStr,
String
" but got: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
actualStr,
String
diffLine
]
[Difference]
ds ->
let diffMessages :: String
diffMessages = [Difference] -> String
formatDifferences [Difference]
ds
in String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n"
[ String
mainMessage,
String
diffMessages,
String
"",
String
"Full context:",
String
" expected: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
expectedStr,
String
" but got: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
actualStr,
String
diffLine
]
diffPointer :: String -> String -> String
diffPointer :: String -> String -> String
diffPointer String
expected String
actual =
let commonPrefixLen :: Int
commonPrefixLen = [Bool] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Bool] -> Int) -> [Bool] -> Int
forall a b. (a -> b) -> a -> b
$ (Bool -> Bool) -> [Bool] -> [Bool]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile Bool -> Bool
forall a. a -> a
id ([Bool] -> [Bool]) -> [Bool] -> [Bool]
forall a b. (a -> b) -> a -> b
$ (Char -> Char -> Bool) -> String -> String -> [Bool]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
(==) String
expected String
actual
diffLen :: Int
diffLen = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
expected) (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
actual) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
commonPrefixLen
in Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
commonPrefixLen Char
' ' String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
diffLen Char
'^'
mockNameLabel :: Maybe MockName -> String
mockNameLabel :: Maybe String -> String
mockNameLabel = String -> (String -> String) -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
forall a. Monoid a => a
mempty (String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<>) (Maybe String -> String)
-> (Maybe String -> Maybe String) -> Maybe String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe String -> Maybe String
enclose String
"`"
enclose :: String -> Maybe String -> Maybe String
enclose :: String -> Maybe String -> Maybe String
enclose String
e = (String -> String) -> Maybe String -> Maybe String
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\String
v -> String
e String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
v String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
e)
formatStr :: String -> String
formatStr :: String -> String
formatStr String
s =
case String
s of
[] -> String
s
Char
c:String
cs ->
case String -> String
forall a. [a] -> [a]
reverse String
cs of
[] -> String -> String
formatInner String
s
Char
l:String
ls ->
let inner :: String
inner = String -> String
forall a. [a] -> [a]
reverse String
ls
in case (Char
c, Char
l) of
(Char
'(', Char
')') -> String
"(" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String
formatInner String
inner String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
")"
(Char
'[', Char
')') -> String
"[" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String
formatInner String
inner String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"]"
(Char
'[', Char
']') -> String
"[" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String
formatInner String
inner String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"]"
(Char
'{', Char
'}') -> String
"{" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String
formatInner String
inner String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"}"
(Char, Char)
_ -> String -> String
formatInner String
s
where
formatInner :: String -> String
formatInner String
inner =
let tokens :: [String]
tokens = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String
trim (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
quoteToken (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
trim) (String -> [String]
splitByComma String
inner)
in String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " [String]
tokens
quoteToken :: String -> String
quoteToken :: String -> String
quoteToken String
s = case String
s of
[] -> String
s
Char
'"':String
_ -> String
s
Char
'(':String
_ -> String
s
Char
'[':String
_ -> String
s
Char
c:String
_
| (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Char -> Bool
isSpecial String
s -> String
s
| Char -> Bool
isLower Char
c -> Char
'"' Char -> String -> String
forall a. a -> [a] -> [a]
: String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\""
| Bool
otherwise -> String
s
where
isSpecial :: Char -> Bool
isSpecial Char
c = Char
c Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
"{}= "
verifyFailedMessage :: Show a => Maybe MockName -> InvocationList a -> a -> VerifyFailed
verifyFailedMessage :: forall a.
Show a =>
Maybe String -> InvocationList a -> a -> VerifyFailed
verifyFailedMessage Maybe String
name InvocationList a
invocationList a
expected =
let expectedStr :: String
expectedStr = String -> String
formatStr (a -> String
forall a. Show a => a -> String
show a
expected)
actualStr :: String
actualStr = InvocationList a -> String
forall a. Show a => InvocationList a -> String
formatInvocationList InvocationList a
invocationList
diffLine :: String
diffLine = String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String -> String
diffPointer String
expectedStr String
actualStr
mainMessage :: String
mainMessage = String
"function" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Maybe String -> String
mockNameLabel Maybe String
name String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" was not called with the expected arguments."
in String -> VerifyFailed
VerifyFailed (String -> VerifyFailed) -> String -> VerifyFailed
forall a b. (a -> b) -> a -> b
$ case String -> String -> [Difference]
structuralDiff String
expectedStr String
actualStr of
[] ->
String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n"
[ String
mainMessage,
String
" expected: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
expectedStr,
String
" but got: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
actualStr,
String
diffLine
]
[Difference]
ds ->
let diffMessages :: String
diffMessages = [Difference] -> String
formatDifferences [Difference]
ds
in String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n"
[ String
mainMessage,
String
diffMessages,
String
"",
String
"Full context:",
String
" expected: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
expectedStr,
String
" but got: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
actualStr,
String
diffLine
]
data Difference = Difference
{ Difference -> String
diffPath :: String,
Difference -> String
diffExpected :: String,
Difference -> String
diffActual :: String
}
deriving (Int -> Difference -> String -> String
[Difference] -> String -> String
Difference -> String
(Int -> Difference -> String -> String)
-> (Difference -> String)
-> ([Difference] -> String -> String)
-> Show Difference
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> Difference -> String -> String
showsPrec :: Int -> Difference -> String -> String
$cshow :: Difference -> String
show :: Difference -> String
$cshowList :: [Difference] -> String -> String
showList :: [Difference] -> String -> String
Show, Difference -> Difference -> Bool
(Difference -> Difference -> Bool)
-> (Difference -> Difference -> Bool) -> Eq Difference
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Difference -> Difference -> Bool
== :: Difference -> Difference -> Bool
$c/= :: Difference -> Difference -> Bool
/= :: Difference -> Difference -> Bool
Eq)
formatDifferences :: [Difference] -> String
formatDifferences :: [Difference] -> String
formatDifferences [Difference
d] =
let label :: String
label = if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Difference -> String
diffPath Difference
d) then String
"Specific difference:" else String
"Specific difference in `" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Difference -> String
diffPath Difference
d String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"`:"
in String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n"
[ String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
label,
String
" expected: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Difference -> String
diffExpected Difference
d,
String
" but got: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Difference -> String
diffActual Difference
d,
String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String -> String
diffPointer (Difference -> String
diffExpected Difference
d) (Difference -> String
diffActual Difference
d)
]
formatDifferences [Difference]
ds =
String
" Specific differences:\n" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" ((Difference -> String) -> [Difference] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Difference -> String
formatDiff [Difference]
ds)
where
formatDiff :: Difference -> String
formatDiff Difference
d =
let pathLabel :: String
pathLabel = if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Difference -> String
diffPath Difference
d) then String
"root" else String
"`" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Difference -> String
diffPath Difference
d String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"`"
in String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n"
[ String
" - " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
pathLabel String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
":",
String
" expected: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Difference -> String
diffExpected Difference
d,
String
" but got: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Difference -> String
diffActual Difference
d
]
structuralDiff :: String -> String -> [Difference]
structuralDiff :: String -> String -> [Difference]
structuralDiff = String -> String -> String -> [Difference]
structuralDiff' String
""
structuralDiff' :: String -> String -> String -> [Difference]
structuralDiff' :: String -> String -> String -> [Difference]
structuralDiff' String
path String
expected String
actual
| String -> Bool
isList String
expected Bool -> Bool -> Bool
&& String -> Bool
isList String
actual = String -> String -> String -> [Difference]
diffLists String
path String
expected String
actual
| String -> Bool
isRecord String
expected Bool -> Bool -> Bool
&& String -> Bool
isRecord String
actual = String -> String -> String -> [Difference]
diffRecords String
path String
expected String
actual
| Bool
otherwise = []
diffLists :: String -> String -> String -> [Difference]
diffLists :: String -> String -> String -> [Difference]
diffLists String
path String
expected String
actual =
let items1 :: [String]
items1 = String -> [String]
extractListItems String
expected
items2 :: [String]
items2 = String -> [String]
extractListItems String
actual
indexedMismatches :: [(Int, (String, String))]
indexedMismatches = ((Int, (String, String)) -> Bool)
-> [(Int, (String, String))] -> [(Int, (String, String))]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(Int
_, (String
i1, String
i2)) -> String
i1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= String
i2) ([Int] -> [(String, String)] -> [(Int, (String, String))]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 :: Int ..] ([String] -> [String] -> [(String, String)]
forall a b. [a] -> [b] -> [(a, b)]
zip [String]
items1 [String]
items2))
in ((Int, (String, String)) -> [Difference])
-> [(Int, (String, String))] -> [Difference]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\(Int
idx, (String
i1, String
i2)) ->
let newPath :: String
newPath = String
path String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"[" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
idx String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"]"
nested :: [Difference]
nested = String -> String -> String -> [Difference]
structuralDiff' String
newPath String
i1 String
i2
in if [Difference] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Difference]
nested
then [String -> String -> String -> Difference
Difference String
newPath String
i1 String
i2]
else [Difference]
nested
) [(Int, (String, String))]
indexedMismatches
diffRecords :: String -> String -> String -> [Difference]
diffRecords :: String -> String -> String -> [Difference]
diffRecords String
path String
expected String
actual =
let fields1 :: [String]
fields1 = String -> [String]
extractFields String
expected
fields2 :: [String]
fields2 = String -> [String]
extractFields String
actual
mismatches :: [(String, String)]
mismatches = ((String, String) -> Bool)
-> [(String, String)] -> [(String, String)]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(String
f1, String
f2) -> String
f1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= String
f2 Bool -> Bool -> Bool
&& String -> Bool
isField String
f1 Bool -> Bool -> Bool
&& String -> Bool
isField String
f2) ([String] -> [String] -> [(String, String)]
forall a b. [a] -> [b] -> [(a, b)]
zip [String]
fields1 [String]
fields2)
in ((String, String) -> [Difference])
-> [(String, String)] -> [Difference]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\(String
f1, String
f2) ->
let fieldName :: String
fieldName = String -> String
getFieldName String
f1
val1 :: String
val1 = String -> String
getFieldValue String
f1
val2 :: String
val2 = String -> String
getFieldValue String
f2
newPath :: String
newPath = if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
path then String
fieldName else String
path String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
fieldName
nested :: [Difference]
nested = String -> String -> String -> [Difference]
structuralDiff' String
newPath String
val1 String
val2
in if [Difference] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Difference]
nested
then [String -> String -> String -> Difference
Difference String
newPath String
val1 String
val2]
else [Difference]
nested
) [(String, String)]
mismatches
trim :: String -> String
trim :: String -> String
trim = String -> String
f (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
f
where
f :: String -> String
f = String -> String
forall a. [a] -> [a]
reverse (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ')
splitByComma :: String -> [String]
splitByComma :: String -> [String]
splitByComma = Int -> Int -> Int -> String -> String -> [String]
forall {a} {a} {a}.
(Num a, Num a, Num a, Ord a, Ord a, Ord a) =>
a -> a -> a -> String -> String -> [String]
go (Int
0 :: Int) (Int
0 :: Int) (Int
0 :: Int) String
""
where
go :: a -> a -> a -> String -> String -> [String]
go a
_ a
_ a
_ String
acc [] = [String -> String
trim (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
forall a. [a] -> [a]
reverse String
acc | Bool -> Bool
not (String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
acc)]
go a
p a
l a
b String
acc (Char
c : String
cs)
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'(' = a -> a -> a -> String -> String -> [String]
go (a
p a -> a -> a
forall a. Num a => a -> a -> a
+ a
1) a
l a
b (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
acc) String
cs
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
')' = a -> a -> a -> String -> String -> [String]
go (a -> a -> a
forall a. Ord a => a -> a -> a
max a
0 (a
p a -> a -> a
forall a. Num a => a -> a -> a
- a
1)) a
l a
b (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
acc) String
cs
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'[' = a -> a -> a -> String -> String -> [String]
go a
p (a
l a -> a -> a
forall a. Num a => a -> a -> a
+ a
1) a
b (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
acc) String
cs
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
']' = a -> a -> a -> String -> String -> [String]
go a
p (a -> a -> a
forall a. Ord a => a -> a -> a
max a
0 (a
l a -> a -> a
forall a. Num a => a -> a -> a
- a
1)) a
b (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
acc) String
cs
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'{' = a -> a -> a -> String -> String -> [String]
go a
p a
l (a
b a -> a -> a
forall a. Num a => a -> a -> a
+ a
1) (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
acc) String
cs
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'}' = a -> a -> a -> String -> String -> [String]
go a
p a
l (a -> a -> a
forall a. Ord a => a -> a -> a
max a
0 (a
b a -> a -> a
forall a. Num a => a -> a -> a
- a
1)) (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
acc) String
cs
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
',' Bool -> Bool -> Bool
&& a
p a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 Bool -> Bool -> Bool
&& a
l a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 Bool -> Bool -> Bool
&& a
b a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = String -> String
trim (String -> String
forall a. [a] -> [a]
reverse String
acc) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: a -> a -> a -> String -> String -> [String]
go a
0 a
0 a
0 String
"" String
cs
| Bool
otherwise = a -> a -> a -> String -> String -> [String]
go a
p a
l a
b (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
acc) String
cs
formatInvocationList :: Show a => InvocationList a -> String
formatInvocationList :: forall a. Show a => InvocationList a -> String
formatInvocationList InvocationList a
invocationList = case InvocationList a
invocationList of
[] -> String
"Function was never called"
[a
x] -> String -> String
formatStr (a -> String
forall a. Show a => a -> String
show a
x)
InvocationList a
_ -> String
"[" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " ((a -> String) -> InvocationList a -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String
formatStr (String -> String) -> (a -> String) -> a -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show) InvocationList a
invocationList) String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"]"
_replace :: Show a => String -> a -> String
_replace :: forall a. Show a => String -> a -> String
_replace String
r a
s = Text -> String
unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ HasCallStack => Text -> Text -> Text -> Text
Text -> Text -> Text -> Text
replace (String -> Text
pack String
r) (String -> Text
pack String
"") (String -> Text
pack (a -> String
forall a. Show a => a -> String
show a
s))
messageForMultiMock :: Show a => Maybe MockName -> [a] -> a -> String
messageForMultiMock :: forall a. Show a => Maybe String -> [a] -> a -> String
messageForMultiMock Maybe String
name [a]
expecteds a
actual =
let expectedStrs :: [String]
expectedStrs = (a -> String) -> [a] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String
formatStr (String -> String) -> (a -> String) -> a -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show) [a]
expecteds
actualStr :: String
actualStr = String -> String
formatStr (a -> String
forall a. Show a => a -> String
show a
actual)
nearest :: String
nearest = String -> [String] -> String
chooseNearest String
actualStr [String]
expectedStrs
in String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate
String
"\n"
[ String
"function" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Maybe String -> String
mockNameLabel Maybe String
name String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" was not called with the expected arguments.",
String
" expected one of the following:",
String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<>) (String -> String) -> [String] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [String]
expectedStrs,
String
" but got:",
String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
actualStr,
String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String -> String
diffPointer String
nearest String
actualStr
]
chooseNearest :: String -> [String] -> String
chooseNearest :: String -> [String] -> String
chooseNearest String
_ [] = String
""
chooseNearest String
actual [String]
expectations =
let commonPrefixLen :: [b] -> [b] -> Int
commonPrefixLen [b]
s1 [b]
s2 = [Bool] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Bool] -> Int) -> [Bool] -> Int
forall a b. (a -> b) -> a -> b
$ (Bool -> Bool) -> [Bool] -> [Bool]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile Bool -> Bool
forall a. a -> a
id ([Bool] -> [Bool]) -> [Bool] -> [Bool]
forall a b. (a -> b) -> a -> b
$ (b -> b -> Bool) -> [b] -> [b] -> [Bool]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith b -> b -> Bool
forall a. Eq a => a -> a -> Bool
(==) [b]
s1 [b]
s2
scores :: [(Int, String)]
scores = (String -> (Int, String)) -> [String] -> [(Int, String)]
forall a b. (a -> b) -> [a] -> [b]
map (\String
e -> (String -> String -> Int
forall {b}. Eq b => [b] -> [b] -> Int
commonPrefixLen String
actual String
e, String
e)) [String]
expectations
in (Int, String) -> String
forall a b. (a, b) -> b
snd ((Int, String) -> String) -> (Int, String) -> String
forall a b. (a -> b) -> a -> b
$ ((Int, String) -> (Int, String) -> Ordering)
-> [(Int, String)] -> (Int, String)
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
maximumBy (((Int, String) -> Int)
-> (Int, String) -> (Int, String) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (Int, String) -> Int
forall a b. (a, b) -> a
fst) [(Int, String)]
scores
isRecord :: String -> Bool
isRecord :: String -> Bool
isRecord String
s = Char
'{' Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
s Bool -> Bool -> Bool
&& Char
'}' Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
s
extractFields :: String -> [String]
String
s = [String] -> (String -> [String]) -> Maybe String -> [String]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] String -> [String]
splitByComma (Char -> Char -> String -> Maybe String
extractInner Char
'{' Char
'}' String
s)
extractInner :: Char -> Char -> String -> Maybe String
Char
open Char
close String
s =
case (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
open) String
s of
(Char
x:String
rest) | Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
open -> String -> Maybe String
forall a. a -> Maybe a
Just (Int -> String -> String
takeBalanced (Int
1 :: Int) String
rest)
String
_ -> Maybe String
forall a. Maybe a
Nothing
where
takeBalanced :: Int -> String -> String
takeBalanced :: Int -> String -> String
takeBalanced Int
0 String
_ = String
""
takeBalanced Int
_ [] = String
""
takeBalanced Int
n (Char
c:String
cs)
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
open = Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> String -> String
takeBalanced (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) String
cs
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
close = if Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 then String
"" else Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> String -> String
takeBalanced (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) String
cs
| Bool
otherwise = Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> String -> String
takeBalanced Int
n String
cs
isField :: String -> Bool
isField :: String -> Bool
isField = (Char
'=' Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem`)
getFieldName :: String -> String
getFieldName :: String -> String
getFieldName = String -> String
trim (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'=')
getFieldValue :: String -> String
getFieldValue :: String -> String
getFieldValue = String -> String
trim (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String -> String
forall a. Int -> [a] -> [a]
drop Int
1 (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'=')
isList :: String -> Bool
isList :: String -> Bool
isList String
s = case String
s of
Char
'[':String
cs -> case String -> String
forall a. [a] -> [a]
reverse String
cs of
Char
']':String
_ -> Bool
True
String
_ -> Bool
False
String
_ -> Bool
False
extractListItems :: String -> [String]
String
s = [String] -> (String -> [String]) -> Maybe String -> [String]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] String -> [String]
splitByComma (Char -> Char -> String -> Maybe String
extractInner Char
'[' Char
']' String
s)
listMismatchIndex :: [String] -> [String] -> Maybe Int
listMismatchIndex :: [String] -> [String] -> Maybe Int
listMismatchIndex [String]
s1 [String]
s2 = Bool -> [Bool] -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
elemIndex Bool
False ((String -> String -> Bool) -> [String] -> [String] -> [Bool]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith String -> String -> Bool
forall a. Eq a => a -> a -> Bool
(==) [String]
s1 [String]
s2)
verifyOrderFailedMesssage :: Show a => VerifyOrderResult a -> String
verifyOrderFailedMesssage :: forall a. Show a => VerifyOrderResult a -> String
verifyOrderFailedMesssage VerifyOrderResult {Int
index :: Int
index :: forall a. VerifyOrderResult a -> Int
index, a
calledValue :: a
calledValue :: forall a. VerifyOrderResult a -> a
calledValue, a
expectedValue :: a
expectedValue :: forall a. VerifyOrderResult a -> a
expectedValue} =
let callIndex :: String
callIndex = Int -> String
showHumanReadable (Int
index Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
expectedStr :: String
expectedStr = String -> String
formatStr (a -> String
forall a. Show a => a -> String
show a
expectedValue)
actualStr :: String
actualStr = String -> String
formatStr (a -> String
forall a. Show a => a -> String
show a
calledValue)
prefix :: String
prefix = String
" but got " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
callIndex String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" call: "
spaces :: String
spaces = Int -> Char -> String
forall a. Int -> a -> [a]
replicate (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
prefix) Char
' '
in String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate
String
"\n"
[ String
" expected " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
callIndex String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" call: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
expectedStr,
String
prefix String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
actualStr,
String
spaces String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String -> String
diffPointer String
expectedStr String
actualStr
]
where
showHumanReadable :: Int -> String
showHumanReadable :: Int -> String
showHumanReadable Int
1 = String
"1st"
showHumanReadable Int
2 = String
"2nd"
showHumanReadable Int
3 = String
"3rd"
showHumanReadable Int
n = Int -> String
forall a. Show a => a -> String
show Int
n String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"th"