File: StripTrailingSpace.hs

package info (click to toggle)
haskell-prettyprinter 1.7.1-3
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 372 kB
  • sloc: haskell: 2,453; ansic: 16; makefile: 6
file content (97 lines) | stat: -rw-r--r-- 3,767 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
{-# LANGUAGE CPP               #-}
{-# LANGUAGE OverloadedStrings #-}

#include "version-compatibility-macros.h"

module StripTrailingSpace (testStripTrailingSpace) where



import           Data.Text (Text)
import qualified Data.Text as T

import Prettyprinter
import Prettyprinter.Render.Util.StackMachine

import Test.Tasty
import Test.Tasty.HUnit

#if !(APPLICATIVE_MONAD)
import Control.Applicative
#endif



box :: Text -> Text
box singleLine = unlines'
    [ "┌─" <> T.replicate (T.length singleLine) "─" <> "─┐"
    , "│ " <> singleLine <> " │"
    , "└─" <> T.replicate (T.length singleLine) "─" <> "─┘"
    ]

bbox :: Text -> Text
bbox singleLine = unlines'
    [ "╔═" <> T.replicate (T.length singleLine) "═" <> "═╗"
    , "║ " <> singleLine <> " ║"
    , "╚═" <> T.replicate (T.length singleLine) "═" <> "═╝"
    ]

testStripTrailingSpace :: TestTree
testStripTrailingSpace = testGroup "Stripping trailing space"
    [ testCase "No trailing space"
               (testStripping "No trailing space at all")
    , testCase "Single trailing space character"
               (testStripping ("Single trailing character" <> " "))
    , testCase "Space character inside"
               (testStripping ("Space character" <> " " <> "inside"))
    , testCase "Obvious trailing spaces"
               (testStripping ("Obvious trailing space" <> "   "))
    , testCase "Multiple spaces inside"
               (testStripping ("Multiple spaces" <> "    " <> "inside"))
    , testCase "Whitespace inside text"
               (testStripping "Whitespace inside text   ")
    , testCase "Indented blank line"
               (testStripping (nest 4 (vcat ["Indented blank line", "", "<end>"])))
    , testCase "Multiple indented blank lines"
               (testStripping (nest 4 (vcat ["Indented blank lines", "", "", "", "<end>"])))
    , testCase "Annotation"
               (testStripping (annotate () "Annotation with trailing space   "))
    , testCase "Document with annotation"
               (testStripping ("Here comes an" <> annotate () "annotation   " <> "and some trailing space again  " <> "  "))
    , testCase "Nested annotations"
               (testStripping ("A " <> annotate () ("nested   " <> annotate () "annotation ") <> "and some trailing space again  " <> "  "))
    , testCase "Stress test"
               (testStripping (nest 4 (vcat ["Stress test", "", "" <> annotate () "hello ", "", "world " <> "   ", annotate () "", "", "end"])))
    ]

testStripping :: Doc ann -> Assertion
testStripping doc = case hasTrailingWhitespace (render removeTrailingWhitespace doc) of
    False -> pure ()
    True  -> (assertFailure . T.unpack . T.unlines)
        [ bbox "Input is not stripped correctly!"
        , ""
        , box "Rendered/stripped:"
        , (revealSpaces . render removeTrailingWhitespace) doc
        , ""
        , box "Rendered/unstripped:"
        , (revealSpaces . render id) doc
        , ""
        , box "Rendered/unstripped, later stripped via Text API:"
        , (revealSpaces . removeTrailingSpaceText . render id) doc ]
  where

    render :: (SimpleDocStream ann -> SimpleDocStream ann) -> Doc ann -> Text
    render f = renderSimplyDecorated id (const "<ann>") (const "</ann>") . f . layoutPretty defaultLayoutOptions

    removeTrailingSpaceText :: Text -> Text
    removeTrailingSpaceText = unlines' . map T.stripEnd . T.lines

    hasTrailingWhitespace :: Text -> Bool
    hasTrailingWhitespace x = removeTrailingSpaceText x /= x

    revealSpaces :: Text -> Text
    revealSpaces = T.map (\x -> if x == ' ' then '␣' else x)

-- Text.unlines appends a trailing whitespace, so T.unlines . T.lines /= id
unlines' :: [Text] -> Text
unlines' = T.intercalate (T.singleton '\n')