packages feed

hindent-5.2.0: TESTS.md

# Introduction

This file is a test suite. Each section maps to an HSpec test, and
each line that is followed by a Haskell code fence is tested to make
sure re-formatting that code snippet produces the same result.

You can browse through this document to see what HIndent's style is
like, or contribute additional sections to it, or regression tests.

# Modules

Module header

``` haskell
module X where

x = 1
```

Exports

``` haskell
module X
  ( x
  , y
  , Z
  , P(x, z)
  ) where
```

## Imports

Import lists

``` haskell
import Data.Text
import Data.Text
import qualified Data.Text as T
import qualified Data.Text (a, b, c)
import Data.Text (a, b, c)
import Data.Text hiding (a, b, c)
```

# Declarations

Type declaration

``` haskell
type EventSource a = (AddHandler a, a -> IO ())
```

Instance declaration without decls

``` haskell
instance C a
```

Instance declaration with decls

``` haskell
instance C a where
  foobar = do
    x y
    k p

```
# Expressions

Lazy patterns in a lambda

``` haskell
f = \ ~a -> undefined
 -- \~a yields parse error on input ‘\~’
```

Bang patterns in a lambda

``` haskell
f = \ !a -> undefined
 -- \!a yields parse error on input ‘\!’
```

List comprehensions

``` haskell
defaultExtensions =
  [ e
  | e@EnableExtension {} <- knownExtensions ] \\
  map EnableExtension badExtensions

```
Record indentation

``` haskell
getGitProvider :: EventProvider GitRecord ()
getGitProvider =
  EventProvider
  { getModuleName = "Git"
  , getEvents = getRepoCommits
  }

```
Records again

``` haskell
commitToEvent :: FolderPath -> TimeZone -> Commit -> Event.Event
commitToEvent gitFolderPath timezone commit =
  Event.Event
  { pluginName = getModuleName getGitProvider
  , eventIcon = "glyphicon-cog"
  , eventDate = localTimeToUTC timezone (commitDate commit)
  }

```
Cases

``` haskell
strToMonth :: String -> Int
strToMonth month =
  case month of
    "Jan" -> 1
    "Feb" -> 2
    _ -> error $ "Unknown month " ++ month

```
Operators

``` haskell
x =
  Value <$> thing <*> secondThing <*> thirdThing <*> fourthThing <*> Just thisissolong <*>
  Just stilllonger

```
# Type signatures

Class constraints

``` haskell
fun
  :: (Class a, Class b)
  => a -> b -> c

```
Tuples

``` haskell
fun :: (a, b, c) -> (a, b)
```

# Function declarations

Where clause

``` haskell
sayHello = do
  name <- getLine
  putStrLn $ greeting name
  where
    greeting name = "Hello, " ++ name ++ "!"
```

Guards and pattern guards

``` haskell
f x
  | x <- Just x
  , x <- Just x =
    case x of
      Just x -> e
  | otherwise = do e
  where
    x = y
```

Multi-way if

``` haskell
x =
  if | x <- Just x,
       x <- Just x ->
       case x of
         Just x -> e
         Nothing -> p
     | otherwise -> e

```
Case inside a `where` and `do`

``` haskell
g x =
  case x of
    a -> x
  where
    foo =
      case x of
        _ -> do
          launchMissiles
      where
        y = 2
```

Let inside a `where`

``` haskell
g x =
  let x = 1
  in x
  where
    foo =
      let y = 2
          z = 3
      in y

```
Lists

``` haskell
exceptions = [InvalidStatusCode, MissingContentHeader, InternalServerError]

exceptions =
  [ InvalidStatusCode
  , MissingContentHeader
  , InternalServerError
  , InvalidStatusCode
  , MissingContentHeader
  , InternalServerError]

```
# Johan Tibell compatibility checks

Basic example from Tibbe's style

``` haskell
sayHello :: IO ()
sayHello = do
  name <- getLine
  putStrLn $ greeting name
  where
    greeting name = "Hello, " ++ name ++ "!"

filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter p (x:xs)
  | p x = x : filter p xs
  | otherwise = filter p xs

```
Data declarations

``` haskell
data Tree a
  = Branch !a
           !(Tree a)
           !(Tree a)
  | Leaf

data HttpException
  = InvalidStatusCode Int
  | MissingContentHeader

data Person = Person
  { firstName :: !String -- ^ First name
  , lastName :: !String -- ^ Last name
  , age :: !Int -- ^ Age
  }

```
Spaces between deriving classes

``` haskell
-- From https://github.com/chrisdone/hindent/issues/167
data Person = Person
  { firstName :: !String -- ^ First name
  , lastName :: !String -- ^ Last name
  , age :: !Int -- ^ Age
  } deriving (Eq, Show)

```
Hanging lambdas

``` haskell
bar :: IO ()
bar =
  forM_ [1, 2, 3] $
  \n -> do
    putStrLn "Here comes a number!"
    print n

foo :: IO ()
foo =
  alloca 10 $
  \a ->
     alloca 20 $
     \b -> cFunction fooo barrr muuu (fooo barrr muuu) (fooo barrr muuu)

```
# Comments

Comments within a declaration

``` haskell
bob -- after bob
 =
  foo -- next to foo
  -- line after foo
    (bar
       foo -- next to bar foo
       bar -- next to bar
     ) -- next to the end paren of (bar)
    -- line after (bar)
    mu -- next to mu
    -- line after mu
    -- another line after mu
    zot -- next to zot
    -- line after zot
    (case casey -- after casey
           of
       Just -- after Just
        -> do
         justice -- after justice
          *
           foo
             (blah * blah + z + 2 / 4 + a - -- before a line break
              2 * -- inside this mess
              z /
              2 /
              2 /
              aooooo /
              aaaaa -- bob comment
              ) +
           (sdfsdfsd fsdfsdf) -- blah comment
         putStrLn "")
    [1, 2, 3]
    [ 1 -- foo
    , ( 2 -- bar
      , 2.5 -- mu
       )
    , 3]

foo = 1 -- after foo
```

Haddock comments

``` haskell
-- | Module comment.
module X where

-- | Main doc.
main :: IO ()
main = return ()

data X
  = X -- ^ X is for xylophone.
  | Y -- ^ Y is for why did I eat that pizza.

data X = X
  { field1 :: Int -- ^ Field1 is the first field.
  , field11 :: Char
    -- ^ This field comment is on its own line.
  , field2 :: Int -- ^ Field2 is the second field.
  , field3 :: Char -- ^ This is a long comment which starts next to
    -- the field but continues onto the next line, it aligns exactly
    -- with the field name.
  , field4 :: Char
    -- ^ This is a long comment which starts on the following line
    -- from from the field, lines continue at the sme column.
  }

```
Comments around regular declarations

``` haskell
-- This is some random comment.
-- | Main entry point.
main = putStrLn "Hello, World!"
 -- This is another random comment.
```

## Regression tests

cocreature removed from declaration issue #186

``` haskell
-- https://github.com/chrisdone/hindent/issues/186
trans One e n =
  M.singleton
    (Query Unmarked (Mark NonExistent)) -- The goal of this is to fail always
    (emptyImage
     { notPresent = S.singleton (TransitionResult Two (Just A) n)
     })

```
sheyll explicit forall in instances #218

``` haskell
-- https://github.com/chrisdone/hindent/issues/218
instance forall x. C

instance forall x. Show x =>
         C x
```

tfausak support shebangs #208

``` haskell
#!/usr/bin/env stack
-- stack runghc
main = pure ()
-- https://github.com/chrisdone/hindent/issues/208
```

joe9 preserve newlines between import groups

``` haskell
-- https://github.com/chrisdone/hindent/issues/200
import Data.List
import Data.Maybe

import MyProject
import FooBar

import GHC.Monad

-- blah
import Hello

import CommentAfter -- Comment here shouldn't affect newlines
import HelloWorld

import CommentAfter -- Comment here shouldn't affect newlines

import HelloWorld

-- Comment here shouldn't affect newlines
import CommentAfter

import HelloWorld
```

radupopescu `deriving` keyword not aligned with pipe symbol for type declarations

``` haskell
data Stuffs
  = Things
  | This
  | That
  deriving (Show)

data Simple =
  Simple
  deriving (Show)
```

# Behaviour checks

Unicode

``` haskell
α = γ * "ω"
 -- υ
```

Empty module

``` haskell
```

Trailing newline is preserved

``` haskell
module X where

foo = 123

```

# Complex input

A complex, slow-to-print decl

``` haskell
quasiQuotes =
  [ ( ''[]
    , \(typeVariable:_) _automaticPrinter ->
         (let presentVar = varE (presentVarName typeVariable)
          in lamE
               [varP (presentVarName typeVariable)]
               [|(let typeString = "[" ++ fst $(presentVar) ++ "]"
                  in ( typeString
                     , \xs ->
                          case fst $(presentVar) of
                            "GHC.Types.Char" ->
                              ChoicePresentation
                                "String"
                                [ ( "String"
                                  , StringPresentation
                                      "String"
                                      (concatMap
                                         getCh
                                         (map (snd $(presentVar)) xs)))
                                , ( "List of characters"
                                  , ListPresentation
                                      typeString
                                      (map (snd $(presentVar)) xs))]
                              where getCh (CharPresentation "GHC.Types.Char" ch) =
                                      ch
                                    getCh (ChoicePresentation _ ((_, CharPresentation _ ch):_)) =
                                      ch
                                    getCh _ = ""
                            _ ->
                              ListPresentation
                                typeString
                                (map (snd $(presentVar)) xs)))|]))]
```

Random snippet from hindent itself

``` haskell
exp' (App _ op a) = do
  (fits, st) <- fitsOnOneLine (spaced (map pretty (f : args)))
  if fits
    then put st
    else do
      pretty f
      newline
      spaces <- getIndentSpaces
      indented spaces (lined (map pretty args))
  where
    (f, args) = flatten op [a]
    flatten :: Exp NodeInfo -> [Exp NodeInfo] -> (Exp NodeInfo, [Exp NodeInfo])
    flatten (App _ f' a') b = flatten f' (a' : b)
    flatten f' as = (f', as)
```