packages feed

cimple-0.0.2: test/Language/Cimple/PrettySpec.hs

module Language.Cimple.PrettySpec where

import           Test.Hspec                   (Spec, describe, it, shouldBe)

import qualified Data.Text                    as Text
import           Language.Cimple.IO           (parseText)
import           Language.Cimple.Pretty       (ppTranslationUnit)
import           Text.PrettyPrint.ANSI.Leijen (displayS, renderCompact)

getRight :: Either String a -> a
getRight (Left  err) = error err
getRight (Right ok ) = ok

pretty :: String -> String
pretty =
    show
    . ppTranslationUnit
    . getRight
    . parseText
    . Text.pack

compact :: String -> String
compact =
    flip displayS ""
    . renderCompact
    . ppTranslationUnit
    . getRight
    . parseText
    . Text.pack


spec :: Spec
spec = do
    describe "renderPretty" $ do
        it "pretty-prints a simple C function" $ do
            let pp = pretty "int a(void) { return 3; }"
            pp `shouldBe` unlines
                [ "int a(void)"
                , "{"
                , "  return 3;"
                , "}"
                ]

        it "pretty-prints a typedef struct" $ do
            let pp = pretty "typedef struct Foo { int32_t x; } Foo;"
            pp `shouldBe` unlines
                [ "typedef struct Foo {"
                , "  int32_t x;"
                , "} Foo;"
                ]

    describe "renderCompact" $ do
        it "pretty-prints a simple C function" $ do
            let pp = compact "int a(void) { return 3; }"
            pp `shouldBe` unlines
                [ "int a(void)"
                , "{"
                , "return 3;"
                , "}"
                ]

        it "pretty-prints a typedef struct" $ do
            let pp = compact "typedef struct Foo { int32_t x; } Foo;"
            pp `shouldBe` unlines
                [ "typedef struct Foo {"
                , "int32_t x;"
                , "} Foo;"
                ]

        it "respects newlines at end of comments" $ do
            compact "/* foo bar */" `shouldBe` "/* foo bar */\n"
            compact "/* foo bar\n */" `shouldBe` "/* foo bar\n */\n"

        it "respects comment styles" $ do
            compact "/* foo bar */" `shouldBe` "/* foo bar */\n"
            compact "/** foo bar */ int a(void);" `shouldBe` "/** foo bar */\nint a(void);\n"
            compact "/*** foo bar */" `shouldBe` "/*** foo bar */\n"
            compact "/**** foo bar */" `shouldBe` "/*** foo bar */\n"

        it "supports punctuation in comments" $ do
            compact "/* foo.bar,baz-blep */"
                `shouldBe` "/* foo. bar, baz - blep */\n"
            compact "/* foo? */" `shouldBe` "/* foo ? */\n"

        it "formats number ranges and negative numbers without spacing" $ do
            compact "/* 123 - 456 */" `shouldBe` "/* 123-456 */\n"
            compact "/* - 3 */" `shouldBe` "/* -3 */\n"
            compact "/* a-b */" `shouldBe` "/* a - b */\n"

        it "formats pointer types with east-const" $ do
            compact "void foo(const int *a);"
                `shouldBe` "void foo(int const* a);\n"
            compact "void foo(int const *a);"
                `shouldBe` "void foo(int const* a);\n"

        it "supports type-variables" $ do
            compact "void foo(`a a);" `shouldBe` "void foo(`a a);\n"
            compact "`a id(const `a a) { return a; }"
                `shouldBe` "`a id(`a const a)\n{\nreturn a;\n}\n"

        it "formats expressions and statements" $ do
            compact "void foo() { return 1+2*3/4; }"
                `shouldBe` "void foo()\n{\nreturn 1 + 2 * 3 / 4;\n}\n"
            compact "void foo() { a = ~b << !c; }"
                `shouldBe` "void foo()\n{\na = ~b << !c;\n}\n"
            compact "void foo() { int a[] = {1,2,3}; }"
                `shouldBe` "void foo()\n{\nint a[] = { 1, 2, 3 };\n}\n"

        it "supports variadic functions" $ do
            compact "void foo(int a, ...);"
                `shouldBe` "void foo(int a, ...);\n"
            compact "void foo(int a, const char *msg, ...);"
                `shouldBe` "void foo(int a, char const* msg, ...);\n"

        it "supports C preprocessor directives" $ do
            compact "#define XYZZY 123\n"
                `shouldBe` "#define XYZZY 123\n"
            compact "#include <tox/tox.h>\n"
                `shouldBe` "#include <tox/tox.h>\n"