module Runner.Example (
  Result (..)
, mkResult
) where

import           Imports

import           Data.Char
import           Data.List (isPrefixOf)
import           Util

import           Parse

maxBy :: (Ord a) => (b -> a) -> b -> b -> b
maxBy :: forall a b. Ord a => (b -> a) -> b -> b -> b
maxBy b -> a
f b
x b
y = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (b -> a
f b
x) (b -> a
f b
y) of
  Ordering
LT -> b
y
  Ordering
EQ -> b
x
  Ordering
GT -> b
x

data Result = Equal | NotEqual [String]
  deriving (Result -> Result -> Bool
(Result -> Result -> Bool)
-> (Result -> Result -> Bool) -> Eq Result
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Result -> Result -> Bool
== :: Result -> Result -> Bool
$c/= :: Result -> Result -> Bool
/= :: Result -> Result -> Bool
Eq, Int -> Result -> ShowS
[Result] -> ShowS
Result -> [Char]
(Int -> Result -> ShowS)
-> (Result -> [Char]) -> ([Result] -> ShowS) -> Show Result
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Result -> ShowS
showsPrec :: Int -> Result -> ShowS
$cshow :: Result -> [Char]
show :: Result -> [Char]
$cshowList :: [Result] -> ShowS
showList :: [Result] -> ShowS
Show)

mkResult :: ExpectedResult -> [String] -> Result
mkResult :: ExpectedResult -> [[Char]] -> Result
mkResult ExpectedResult
expected_ [[Char]]
actual_ =
  case ExpectedResult
expected ExpectedResult -> [[Char]] -> Match LinesDivergence
`matches` [[Char]]
actual of
  Match LinesDivergence
Full            -> Result
Equal
  Partial LinesDivergence
partial -> [[Char]] -> Result
NotEqual (ExpectedResult -> [[Char]] -> LinesDivergence -> [[Char]]
formatNotEqual ExpectedResult
expected [[Char]]
actual LinesDivergence
partial)
  where
    -- use show to escape special characters in output lines if any output line
    -- contains any unsafe character
    escapeOutput :: ShowS
escapeOutput
      | (Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSafe) ([Char] -> Bool) -> [Char] -> Bool
forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Char]]
expectedAsString [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [[Char]]
actual_) = ShowS
forall a. HasCallStack => [a] -> [a]
init ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
forall a. HasCallStack => [a] -> [a]
tail ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
forall a. Show a => a -> [Char]
show ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
stripEnd
      | Bool
otherwise = ShowS
forall a. a -> a
id

    actual :: [String]
    actual :: [[Char]]
actual = ShowS -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ShowS
escapeOutput [[Char]]
actual_

    expected :: ExpectedResult
    expected :: ExpectedResult
expected = (ExpectedLine -> ExpectedLine) -> ExpectedResult -> ExpectedResult
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ShowS -> ExpectedLine -> ExpectedLine
transformExcpectedLine ShowS
escapeOutput) ExpectedResult
expected_

    expectedAsString :: [String]
    expectedAsString :: [[Char]]
expectedAsString = (ExpectedLine -> [Char]) -> ExpectedResult -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map (\ExpectedLine
x -> case ExpectedLine
x of
        ExpectedLine [LineChunk]
str -> (LineChunk -> [Char]) -> [LineChunk] -> [Char]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap LineChunk -> [Char]
lineChunkToString [LineChunk]
str
        ExpectedLine
WildCardLine -> [Char]
"..." ) ExpectedResult
expected_

    isSafe :: Char -> Bool
    isSafe :: Char -> Bool
isSafe Char
c = Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ' Bool -> Bool -> Bool
|| (Char -> Bool
isPrint Char
c Bool -> Bool -> Bool
&& (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) Char
c)

    chunksMatch :: [LineChunk] -> String -> Match ChunksDivergence
    chunksMatch :: [LineChunk] -> [Char] -> Match ChunksDivergence
chunksMatch [] [Char]
"" = Match ChunksDivergence
forall a. Match a
Full
    chunksMatch [LineChunk [Char]
xs] [Char]
ys =
      if ShowS
stripEnd [Char]
xs [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== ShowS
stripEnd [Char]
ys
      then Match ChunksDivergence
forall a. Match a
Full
      else ChunksDivergence -> Match ChunksDivergence
forall a. a -> Match a
Partial (ChunksDivergence -> Match ChunksDivergence)
-> ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> ChunksDivergence
matchingPrefix [Char]
xs [Char]
ys
    chunksMatch (LineChunk [Char]
x : [LineChunk]
xs) [Char]
ys =
      if [Char]
x [Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` [Char]
ys
      then (ChunksDivergence -> ChunksDivergence)
-> Match ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> Match a -> Match b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Char] -> ChunksDivergence -> ChunksDivergence
prependText [Char]
x) (Match ChunksDivergence -> Match ChunksDivergence)
-> Match ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> a -> b
$ ([LineChunk]
xs [LineChunk] -> [Char] -> Match ChunksDivergence
`chunksMatch` Int -> ShowS
forall a. Int -> [a] -> [a]
drop ([Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
x) [Char]
ys)
      else ChunksDivergence -> Match ChunksDivergence
forall a. a -> Match a
Partial (ChunksDivergence -> Match ChunksDivergence)
-> ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> ChunksDivergence
matchingPrefix [Char]
x [Char]
ys
    chunksMatch zs :: [LineChunk]
zs@(LineChunk
WildCardChunk : [LineChunk]
xs) (Char
_:[Char]
ys) =
      -- Prefer longer matches.
      (ChunksDivergence -> ChunksDivergence)
-> Match ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> Match a -> Match b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ChunksDivergence -> ChunksDivergence
prependWildcard (Match ChunksDivergence -> Match ChunksDivergence)
-> Match ChunksDivergence -> Match ChunksDivergence
forall a b. (a -> b) -> a -> b
$ (Match ChunksDivergence -> Match Int)
-> Match ChunksDivergence
-> Match ChunksDivergence
-> Match ChunksDivergence
forall a b. Ord a => (b -> a) -> b -> b -> b
maxBy
        ((ChunksDivergence -> Int) -> Match ChunksDivergence -> Match Int
forall a b. (a -> b) -> Match a -> Match b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ChunksDivergence -> Int) -> Match ChunksDivergence -> Match Int)
-> (ChunksDivergence -> Int) -> Match ChunksDivergence -> Match Int
forall a b. (a -> b) -> a -> b
$ [Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Char] -> Int)
-> (ChunksDivergence -> [Char]) -> ChunksDivergence -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ChunksDivergence -> [Char]
matchText)
        ([LineChunk] -> [Char] -> Match ChunksDivergence
chunksMatch [LineChunk]
xs [Char]
ys)
        ([LineChunk] -> [Char] -> Match ChunksDivergence
chunksMatch [LineChunk]
zs [Char]
ys)
    chunksMatch [LineChunk
WildCardChunk] [] = Match ChunksDivergence
forall a. Match a
Full
    chunksMatch (LineChunk
WildCardChunk:[LineChunk]
_) [] = ChunksDivergence -> Match ChunksDivergence
forall a. a -> Match a
Partial ([Char] -> [Char] -> ChunksDivergence
ChunksDivergence [Char]
"" [Char]
"")
    chunksMatch [] (Char
_:[Char]
_) = ChunksDivergence -> Match ChunksDivergence
forall a. a -> Match a
Partial ([Char] -> [Char] -> ChunksDivergence
ChunksDivergence [Char]
"" [Char]
"")

    matchingPrefix :: [Char] -> [Char] -> ChunksDivergence
matchingPrefix [Char]
xs [Char]
ys =
      let common :: [Char]
common = ((Char, Char) -> Char) -> [(Char, Char)] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Char, Char) -> Char
forall a b. (a, b) -> a
fst (((Char, Char) -> Bool) -> [(Char, Char)] -> [(Char, Char)]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (\(Char
x, Char
y) -> Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
y) ([Char]
xs [Char] -> [Char] -> [(Char, Char)]
forall a b. [a] -> [b] -> [(a, b)]
`zip` [Char]
ys)) in
      [Char] -> [Char] -> ChunksDivergence
ChunksDivergence [Char]
common [Char]
common

    matches :: ExpectedResult -> [String] -> Match LinesDivergence
    matches :: ExpectedResult -> [[Char]] -> Match LinesDivergence
matches (ExpectedLine [LineChunk]
x : ExpectedResult
xs) ([Char]
y : [[Char]]
ys) =
      case [LineChunk]
x [LineChunk] -> [Char] -> Match ChunksDivergence
`chunksMatch` [Char]
y of
      Match ChunksDivergence
Full -> (LinesDivergence -> LinesDivergence)
-> Match LinesDivergence -> Match LinesDivergence
forall a b. (a -> b) -> Match a -> Match b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LinesDivergence -> LinesDivergence
incLineNo (Match LinesDivergence -> Match LinesDivergence)
-> Match LinesDivergence -> Match LinesDivergence
forall a b. (a -> b) -> a -> b
$ ExpectedResult
xs ExpectedResult -> [[Char]] -> Match LinesDivergence
`matches` [[Char]]
ys
      Partial ChunksDivergence
partial -> LinesDivergence -> Match LinesDivergence
forall a. a -> Match a
Partial (Int -> [Char] -> LinesDivergence
LinesDivergence Int
1 (ChunksDivergence -> [Char]
expandedWildcards ChunksDivergence
partial))
    matches zs :: ExpectedResult
zs@(ExpectedLine
WildCardLine : ExpectedResult
xs) us :: [[Char]]
us@([Char]
_ : [[Char]]
ys) =
      -- Prefer longer matches, and later ones of equal length.
      let matchWithoutWC :: Match LinesDivergence
matchWithoutWC = ExpectedResult
xs ExpectedResult -> [[Char]] -> Match LinesDivergence
`matches` [[Char]]
us in
      let matchWithWC :: Match LinesDivergence
matchWithWC    = (LinesDivergence -> LinesDivergence)
-> Match LinesDivergence -> Match LinesDivergence
forall a b. (a -> b) -> Match a -> Match b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LinesDivergence -> LinesDivergence
incLineNo (ExpectedResult
zs ExpectedResult -> [[Char]] -> Match LinesDivergence
`matches` [[Char]]
ys) in
      let key :: LinesDivergence -> (Int, Int)
key (LinesDivergence Int
lineNo [Char]
line) = ([Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
line, Int
lineNo) in
      (Match LinesDivergence -> Match (Int, Int))
-> Match LinesDivergence
-> Match LinesDivergence
-> Match LinesDivergence
forall a b. Ord a => (b -> a) -> b -> b -> b
maxBy ((LinesDivergence -> (Int, Int))
-> Match LinesDivergence -> Match (Int, Int)
forall a b. (a -> b) -> Match a -> Match b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LinesDivergence -> (Int, Int)
key) Match LinesDivergence
matchWithoutWC Match LinesDivergence
matchWithWC
    matches [ExpectedLine
WildCardLine] [] = Match LinesDivergence
forall a. Match a
Full
    matches [] [] = Match LinesDivergence
forall a. Match a
Full
    matches [] [[Char]]
_  = LinesDivergence -> Match LinesDivergence
forall a. a -> Match a
Partial (Int -> [Char] -> LinesDivergence
LinesDivergence Int
1 [Char]
"")
    matches ExpectedResult
_  [] = LinesDivergence -> Match LinesDivergence
forall a. a -> Match a
Partial (Int -> [Char] -> LinesDivergence
LinesDivergence Int
1 [Char]
"")

-- Note: order of constructors matters, so that full matches sort as
-- greater than partial.
data Match a = Partial a | Full
  deriving (Match a -> Match a -> Bool
(Match a -> Match a -> Bool)
-> (Match a -> Match a -> Bool) -> Eq (Match a)
forall a. Eq a => Match a -> Match a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => Match a -> Match a -> Bool
== :: Match a -> Match a -> Bool
$c/= :: forall a. Eq a => Match a -> Match a -> Bool
/= :: Match a -> Match a -> Bool
Eq, Eq (Match a)
Eq (Match a) =>
(Match a -> Match a -> Ordering)
-> (Match a -> Match a -> Bool)
-> (Match a -> Match a -> Bool)
-> (Match a -> Match a -> Bool)
-> (Match a -> Match a -> Bool)
-> (Match a -> Match a -> Match a)
-> (Match a -> Match a -> Match a)
-> Ord (Match a)
Match a -> Match a -> Bool
Match a -> Match a -> Ordering
Match a -> Match a -> Match a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (Match a)
forall a. Ord a => Match a -> Match a -> Bool
forall a. Ord a => Match a -> Match a -> Ordering
forall a. Ord a => Match a -> Match a -> Match a
$ccompare :: forall a. Ord a => Match a -> Match a -> Ordering
compare :: Match a -> Match a -> Ordering
$c< :: forall a. Ord a => Match a -> Match a -> Bool
< :: Match a -> Match a -> Bool
$c<= :: forall a. Ord a => Match a -> Match a -> Bool
<= :: Match a -> Match a -> Bool
$c> :: forall a. Ord a => Match a -> Match a -> Bool
> :: Match a -> Match a -> Bool
$c>= :: forall a. Ord a => Match a -> Match a -> Bool
>= :: Match a -> Match a -> Bool
$cmax :: forall a. Ord a => Match a -> Match a -> Match a
max :: Match a -> Match a -> Match a
$cmin :: forall a. Ord a => Match a -> Match a -> Match a
min :: Match a -> Match a -> Match a
Ord, Int -> Match a -> ShowS
[Match a] -> ShowS
Match a -> [Char]
(Int -> Match a -> ShowS)
-> (Match a -> [Char]) -> ([Match a] -> ShowS) -> Show (Match a)
forall a. Show a => Int -> Match a -> ShowS
forall a. Show a => [Match a] -> ShowS
forall a. Show a => Match a -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> Match a -> ShowS
showsPrec :: Int -> Match a -> ShowS
$cshow :: forall a. Show a => Match a -> [Char]
show :: Match a -> [Char]
$cshowList :: forall a. Show a => [Match a] -> ShowS
showList :: [Match a] -> ShowS
Show)

instance Functor Match where
  fmap :: forall a b. (a -> b) -> Match a -> Match b
fmap a -> b
f (Partial a
a) = b -> Match b
forall a. a -> Match a
Partial (a -> b
f a
a)
  fmap a -> b
_ Match a
Full = Match b
forall a. Match a
Full

data ChunksDivergence = ChunksDivergence { ChunksDivergence -> [Char]
matchText :: String, ChunksDivergence -> [Char]
expandedWildcards :: String }
  deriving (Int -> ChunksDivergence -> ShowS
[ChunksDivergence] -> ShowS
ChunksDivergence -> [Char]
(Int -> ChunksDivergence -> ShowS)
-> (ChunksDivergence -> [Char])
-> ([ChunksDivergence] -> ShowS)
-> Show ChunksDivergence
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ChunksDivergence -> ShowS
showsPrec :: Int -> ChunksDivergence -> ShowS
$cshow :: ChunksDivergence -> [Char]
show :: ChunksDivergence -> [Char]
$cshowList :: [ChunksDivergence] -> ShowS
showList :: [ChunksDivergence] -> ShowS
Show)

prependText :: String -> ChunksDivergence -> ChunksDivergence
prependText :: [Char] -> ChunksDivergence -> ChunksDivergence
prependText [Char]
s (ChunksDivergence [Char]
mt [Char]
wct) = [Char] -> [Char] -> ChunksDivergence
ChunksDivergence ([Char]
s[Char] -> ShowS
forall a. [a] -> [a] -> [a]
++[Char]
mt) ([Char]
s[Char] -> ShowS
forall a. [a] -> [a] -> [a]
++[Char]
wct)

prependWildcard :: ChunksDivergence -> ChunksDivergence
prependWildcard :: ChunksDivergence -> ChunksDivergence
prependWildcard (ChunksDivergence [Char]
mt [Char]
wct) = [Char] -> [Char] -> ChunksDivergence
ChunksDivergence [Char]
mt (Char
'.'Char -> ShowS
forall a. a -> [a] -> [a]
:[Char]
wct)

data LinesDivergence = LinesDivergence { LinesDivergence -> Int
_mismatchLineNo :: Int, LinesDivergence -> [Char]
_partialLine :: String }
  deriving (Int -> LinesDivergence -> ShowS
[LinesDivergence] -> ShowS
LinesDivergence -> [Char]
(Int -> LinesDivergence -> ShowS)
-> (LinesDivergence -> [Char])
-> ([LinesDivergence] -> ShowS)
-> Show LinesDivergence
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LinesDivergence -> ShowS
showsPrec :: Int -> LinesDivergence -> ShowS
$cshow :: LinesDivergence -> [Char]
show :: LinesDivergence -> [Char]
$cshowList :: [LinesDivergence] -> ShowS
showList :: [LinesDivergence] -> ShowS
Show)

incLineNo :: LinesDivergence -> LinesDivergence
incLineNo :: LinesDivergence -> LinesDivergence
incLineNo (LinesDivergence Int
lineNo [Char]
partialLineMatch) = Int -> [Char] -> LinesDivergence
LinesDivergence (Int
lineNo Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) [Char]
partialLineMatch

formatNotEqual :: ExpectedResult -> [String] -> LinesDivergence -> [String]
formatNotEqual :: ExpectedResult -> [[Char]] -> LinesDivergence -> [[Char]]
formatNotEqual ExpectedResult
expected_ [[Char]]
actual LinesDivergence
partial = [Char] -> [[Char]] -> [[Char]]
formatLines [Char]
"expected: " [[Char]]
expected [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [Char] -> [[Char]] -> [[Char]]
formatLines [Char]
" but got: " (Bool -> LinesDivergence -> [[Char]] -> [[Char]]
lineMarker Bool
wildcard LinesDivergence
partial [[Char]]
actual)
  where
    expected :: [String]
    expected :: [[Char]]
expected = (ExpectedLine -> [Char]) -> ExpectedResult -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map (\ExpectedLine
x -> case ExpectedLine
x of
        ExpectedLine [LineChunk]
str -> (LineChunk -> [Char]) -> [LineChunk] -> [Char]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap LineChunk -> [Char]
lineChunkToString [LineChunk]
str
        ExpectedLine
WildCardLine -> [Char]
"..." ) ExpectedResult
expected_

    formatLines :: String -> [String] -> [String]
    formatLines :: [Char] -> [[Char]] -> [[Char]]
formatLines [Char]
message [[Char]]
xs = case [[Char]]
xs of
      [Char]
y:[[Char]]
ys -> ([Char]
message [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
y) [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: ShowS -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map ([Char]
padding [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++) [[Char]]
ys
      []   -> [[Char]
message]
      where
        padding :: [Char]
padding = Int -> Char -> [Char]
forall a. Int -> a -> [a]
replicate ([Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
message) Char
' '

    wildcard :: Bool
    wildcard :: Bool
wildcard = (ExpectedLine -> Bool) -> ExpectedResult -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\ExpectedLine
x -> case ExpectedLine
x of
        ExpectedLine [LineChunk]
xs -> (LineChunk -> Bool) -> [LineChunk] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\LineChunk
y -> case LineChunk
y of { LineChunk
WildCardChunk -> Bool
True; LineChunk
_ -> Bool
False }) [LineChunk]
xs
        ExpectedLine
WildCardLine -> Bool
True ) ExpectedResult
expected_

lineChunkToString :: LineChunk -> String
lineChunkToString :: LineChunk -> [Char]
lineChunkToString LineChunk
WildCardChunk = [Char]
"..."
lineChunkToString (LineChunk [Char]
str) = [Char]
str

transformExcpectedLine :: (String -> String) -> ExpectedLine -> ExpectedLine
transformExcpectedLine :: ShowS -> ExpectedLine -> ExpectedLine
transformExcpectedLine ShowS
f (ExpectedLine [LineChunk]
xs) =
  [LineChunk] -> ExpectedLine
ExpectedLine ([LineChunk] -> ExpectedLine) -> [LineChunk] -> ExpectedLine
forall a b. (a -> b) -> a -> b
$ (LineChunk -> LineChunk) -> [LineChunk] -> [LineChunk]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\LineChunk
el -> case LineChunk
el of
    LineChunk [Char]
s -> [Char] -> LineChunk
LineChunk ([Char] -> LineChunk) -> [Char] -> LineChunk
forall a b. (a -> b) -> a -> b
$ ShowS
f [Char]
s
    LineChunk
WildCardChunk -> LineChunk
WildCardChunk
  ) [LineChunk]
xs
transformExcpectedLine ShowS
_ ExpectedLine
WildCardLine = ExpectedLine
WildCardLine

lineMarker :: Bool -> LinesDivergence -> [String] -> [String]
lineMarker :: Bool -> LinesDivergence -> [[Char]] -> [[Char]]
lineMarker Bool
wildcard (LinesDivergence Int
row [Char]
expanded) [[Char]]
actual =
  let ([[Char]]
pre, [[Char]]
post) = Int -> [[Char]] -> ([[Char]], [[Char]])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
row [[Char]]
actual in
  [[Char]]
pre [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++
  [(if Bool
wildcard Bool -> Bool -> Bool
&& [Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
expanded Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
30
    -- show expanded pattern if match is long, to help understanding what matched what
    then [Char]
expanded
    else Int -> Char -> [Char]
forall a. Int -> a -> [a]
replicate ([Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
expanded) Char
' ') [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
"^"] [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++
  [[Char]]
post