packages feed

fast-tags-0.0.1: src/Main_test.hs

{-# LANGUAGE OverloadedStrings #-}
module Main_test where
import Control.Monad
import qualified Data.Maybe as Maybe
import qualified Data.Text as Text

import qualified Main as Main
import Main (Token, TokenVal(..), TagVal(..), Type(..))


-- This is kind of annoying without line numbers on equal and automatic
-- test_* collection...
main = do
    test_tokenize
    test_breakString
    test_stripComments
    test_process

test_tokenize = do
    let f = extractTokens . tokenize
    equal (f "a::b->c") ["nl 0", "a", "::", "b", "->", "c"]
    equal (f "x{-\n  bc#-}\n")
        ["nl 0", "x", "{-", "nl 2", "bc", "#", "-}"]
    equal (f "X.Y") ["nl 0", "X.Y"]

test_breakString = do
    let f = Main.breakString
    equal (f "hi \" there") ("hi \"", " there")
    equal (f "hi \\a \" there") ("hi \\a \"", " there")
    equal (f "hi \\\" there\"") ("hi \\\" there\"", "")
    equal (f "hi") ("hi", "")
    -- String continuation isn't implemented yet.
    equal (f "hi \\") ("hi \\", "")

test_stripComments = do
    let f = extractTokens . Main.stripComments . tokenize
    equal (f "hello -- there") ["nl 0", "hello"]
    equal (f "hello {- there -} fred") ["nl 0", "hello", "fred"]
    equal (f "{-# LANG #-} hello {- there {- nested -} comment -} fred")
        ["nl 0", "hello", "fred"]

test_breakBlocks = do
    let f = map extractTokens . Main.breakBlocks . tokenize
    equal (f "1\n2\n") [["1"], ["2"]]
    equal (f "1\n 1\n2\n") [["1", "1"], ["2"]]
    equal (f "1\n 1\n 1\n2\n") [["1", "1", "1"], ["2"]]
    -- intervening blank lines are ignored
    equal (f "1\n 1\n\n 1\n2\n") [["1", "1", "1"], ["2"]]
    equal (f "1\n\n\n 1\n2\n") [["1", "1"], ["2"]]

test_process = do
    let f = map Main.valOf . Main.process "fn"
    equal (f "module Bar.Foo where\n") [Tag "Foo" Module]
    equal (f "newtype Foo a b =\n\tBar x y z\n")
        [Tag "Foo" Type, Tag "Bar" Constructor]
    equal (f "data Foo a = Bar { field :: Field }")
        [Tag "Foo" Type, Tag "Bar" Constructor, Tag "field" Function]
    equal (f "data Foo = Bar | Baz")
        [Tag "Foo" Type, Tag "Bar" Constructor, Tag "Baz" Constructor]
    equal (f "class (X x) => C a b c where\n\tm :: a -> b\n\tn :: c -> d\n")
        [Tag "C" Class, Tag "m" Function, Tag "n" Function]
    equal (f "class A a where f :: X\n")
        [Tag "A" Class, Tag "f" Function]
    equal (f "data X\n") [Tag "X" Type]

    -- The extra X is suppressed.
    equal (f "data X = X Int\n") [Tag "X" Type]

    equal (f "f :: A -> B\ng :: C -> D\ndata D = C {\n\tf :: A\n\t}\n")
        [Tag "f" Function, Tag "g" Function, Tag "D" Type,
            Tag "C" Constructor, Tag "f" Function]


tokenize :: Text.Text -> [Token]
tokenize = concat . map Main.tokenize . Main.stripCpp . Main.annotate "fn"

plist :: (Show a) => [a] -> IO ()
plist xs = mapM_ (putStrLn . show) xs >> putChar '\n'

extractTokens :: [Token] -> [Text.Text]
extractTokens = Maybe.mapMaybe $ \token -> case Main.valOf token of
    Token name -> Just name
    Newline n -> Just (Text.pack ("nl " ++ show n))

equal :: (Show a, Eq a) => a -> a -> IO ()
equal x y = unless (x == y) $
    putStrLn $ "__: " ++ show x ++ " /= " ++ show y