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

    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 -> String
    (Int -> Result -> ShowS)
    -> (Result -> String) -> ([Result] -> ShowS) -> Show Result
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Result -> ShowS
    showsPrec :: Int -> Result -> ShowS
    $cshow :: Result -> String
    show :: Result -> String
    $cshowList :: [Result] -> ShowS
    showList :: [Result] -> ShowS
    Show)

    mkResult :: ExpectedResult -> [String] -> Result
    mkResult :: ExpectedResult -> [String] -> Result
    mkResult ExpectedResult
    expected_ [String]
    actual_ =
      case ExpectedResult
    expected ExpectedResult -> [String] -> Match LinesDivergence
    `matches` [String]
    actual of
      Match LinesDivergence
    Full            -> Result
    Equal
      Partial LinesDivergence
    partial -> [String] -> Result
    NotEqual (ExpectedResult -> [String] -> LinesDivergence -> [String]
    formatNotEqual ExpectedResult
    expected [String]
    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) -> String -> 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) (String -> Bool) -> String -> Bool
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat ([String]
    expectedAsString [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [String]
    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 -> String
    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 :: [String]
    actual = ShowS -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ShowS
    escapeOutput [String]
    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 :: [String]
    expectedAsString = (ExpectedLine -> String) -> ExpectedResult -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (\ExpectedLine
    x -> case ExpectedLine
    x of
            ExpectedLine [LineChunk]
    str -> (LineChunk -> String) -> [LineChunk] -> String
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap LineChunk -> String
    lineChunkToString [LineChunk]
    str
            ExpectedLine
    WildCardLine -> String
    "..." ) 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] -> String -> Match ChunksDivergence
    chunksMatch [] String
    "" = Match ChunksDivergence
    forall a. Match a
    Full
        chunksMatch [LineChunk String
    xs] String
    ys =
          if ShowS
    stripEnd String
    xs String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == ShowS
    stripEnd String
    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
    $ String -> String -> ChunksDivergence
    matchingPrefix String
    xs String
    ys
        chunksMatch (LineChunk String
    x : [LineChunk]
    xs) String
    ys =
          if String
    x String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` String
    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 (String -> ChunksDivergence -> ChunksDivergence
    prependText String
    x) (Match ChunksDivergence -> Match ChunksDivergence)
    -> Match ChunksDivergence -> Match ChunksDivergence
    forall a b. (a -> b) -> a -> b
    $ ([LineChunk]
    xs [LineChunk] -> String -> Match ChunksDivergence
    `chunksMatch` Int -> ShowS
    forall a. Int -> [a] -> [a]
    drop (String -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length String
    x) String
    ys)
          else ChunksDivergence -> Match ChunksDivergence
    forall a. a -> Match a
    Partial (ChunksDivergence -> Match ChunksDivergence)
    -> ChunksDivergence -> Match ChunksDivergence
    forall a b. (a -> b) -> a -> b
    $ String -> String -> ChunksDivergence
    matchingPrefix String
    x String
    ys
        chunksMatch zs :: [LineChunk]
    zs@(LineChunk
    WildCardChunk : [LineChunk]
    xs) (Char
    _:String
    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
    $ String -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length (String -> Int)
    -> (ChunksDivergence -> String) -> ChunksDivergence -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ChunksDivergence -> String
    matchText)
            ([LineChunk] -> String -> Match ChunksDivergence
    chunksMatch [LineChunk]
    xs String
    ys)
            ([LineChunk] -> String -> Match ChunksDivergence
    chunksMatch [LineChunk]
    zs String
    ys)
        chunksMatch [LineChunk
    WildCardChunk] [] = Match ChunksDivergence
    forall a. Match a
    Full
        chunksMatch (LineChunk
    WildCardChunk:[LineChunk]
    _) [] = ChunksDivergence -> Match ChunksDivergence
    forall a. a -> Match a
    Partial (String -> String -> ChunksDivergence
    ChunksDivergence String
    "" String
    "")
        chunksMatch [] (Char
    _:String
    _) = ChunksDivergence -> Match ChunksDivergence
    forall a. a -> Match a
    Partial (String -> String -> ChunksDivergence
    ChunksDivergence String
    "" String
    "")

        matchingPrefix :: String -> String -> ChunksDivergence
    matchingPrefix String
    xs String
    ys =
          let common :: String
    common = ((Char, Char) -> Char) -> [(Char, Char)] -> String
    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) (String
    xs String -> String -> [(Char, Char)]
    forall a b. [a] -> [b] -> [(a, b)]
    `zip` String
    ys)) in
          String -> String -> ChunksDivergence
    ChunksDivergence String
    common String
    common

        matches :: ExpectedResult -> [String] -> Match LinesDivergence
        matches :: ExpectedResult -> [String] -> Match LinesDivergence
    matches (ExpectedLine [LineChunk]
    x : ExpectedResult
    xs) (String
    y : [String]
    ys) =
          case [LineChunk]
    x [LineChunk] -> String -> Match ChunksDivergence
    `chunksMatch` String
    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 -> [String] -> Match LinesDivergence
    `matches` [String]
    ys
          Partial ChunksDivergence
    partial -> LinesDivergence -> Match LinesDivergence
    forall a. a -> Match a
    Partial (Int -> String -> LinesDivergence
    LinesDivergence Int
    1 (ChunksDivergence -> String
    expandedWildcards ChunksDivergence
    partial))
        matches zs :: ExpectedResult
    zs@(ExpectedLine
    WildCardLine : ExpectedResult
    xs) us :: [String]
    us@(String
    _ : [String]
    ys) =
          -- Prefer longer matches, and later ones of equal length.
          let matchWithoutWC :: Match LinesDivergence
    matchWithoutWC = ExpectedResult
    xs ExpectedResult -> [String] -> Match LinesDivergence
    `matches` [String]
    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 -> [String] -> Match LinesDivergence
    `matches` [String]
    ys) in
          let key :: LinesDivergence -> (Int, Int)
    key (LinesDivergence Int
    lineNo String
    line) = (String -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length String
    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 [] [String]
    _  = LinesDivergence -> Match LinesDivergence
    forall a. a -> Match a
    Partial (Int -> String -> LinesDivergence
    LinesDivergence Int
    1 String
    "")
        matches ExpectedResult
    _  [] = LinesDivergence -> Match LinesDivergence
    forall a. a -> Match a
    Partial (Int -> String -> LinesDivergence
    LinesDivergence Int
    1 String
    "")

    -- 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 -> String
    (Int -> Match a -> ShowS)
    -> (Match a -> String) -> ([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 -> String
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([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 -> String
    show :: Match a -> String
    $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 -> String
    matchText :: String, ChunksDivergence -> String
    expandedWildcards :: String }
      deriving (Int -> ChunksDivergence -> ShowS
    [ChunksDivergence] -> ShowS
    ChunksDivergence -> String
    (Int -> ChunksDivergence -> ShowS)
    -> (ChunksDivergence -> String)
    -> ([ChunksDivergence] -> ShowS)
    -> Show ChunksDivergence
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> ChunksDivergence -> ShowS
    showsPrec :: Int -> ChunksDivergence -> ShowS
    $cshow :: ChunksDivergence -> String
    show :: ChunksDivergence -> String
    $cshowList :: [ChunksDivergence] -> ShowS
    showList :: [ChunksDivergence] -> ShowS
    Show)

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

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

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

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

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

        formatLines :: String -> [String] -> [String]
        formatLines :: String -> [String] -> [String]
    formatLines String
    message [String]
    xs = case [String]
    xs of
          String
    y:[String]
    ys -> (String
    message String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    y) String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    : ShowS -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String
    padding String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++) [String]
    ys
          []   -> [String
    message]
          where
            padding :: String
    padding = 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
    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 -> String
    lineChunkToString LineChunk
    WildCardChunk = String
    "..."
    lineChunkToString (LineChunk String
    str) = String
    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 String
    s -> String -> LineChunk
    LineChunk (String -> LineChunk) -> String -> LineChunk
    forall a b. (a -> b) -> a -> b
    $ ShowS
    f String
    s
        LineChunk
    WildCardChunk -> LineChunk
    WildCardChunk
      ) [LineChunk]
    xs
    transformExcpectedLine ShowS
    _ ExpectedLine
    WildCardLine = ExpectedLine
    WildCardLine

    lineMarker :: Bool -> LinesDivergence -> [String] -> [String]
    lineMarker :: Bool -> LinesDivergence -> [String] -> [String]
    lineMarker Bool
    wildcard (LinesDivergence Int
    row String
    expanded) [String]
    actual =
      let ([String]
    pre, [String]
    post) = Int -> [String] -> ([String], [String])
    forall a. Int -> [a] -> ([a], [a])
    splitAt Int
    row [String]
    actual in
      [String]
    pre [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++
      [(if Bool
    wildcard Bool -> Bool -> Bool
    && String -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length String
    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 String
    expanded
        else 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
    expanded) Char
    ' ') String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    "^"] [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++
      [String]
    post