packages feed

Frames-0.1.9: test/Spec.hs

{-# LANGUAGE CPP, TemplateHaskell, QuasiQuotes #-}
module Main (manualGeneration, main) where
import Data.List (find)
import Data.Monoid (First(..))
import Language.Haskell.TH as TH
import Language.Haskell.TH.Syntax (addDependentFile)
import Test.Hspec as H
import Frames
import DataCSV
import PrettyTH

-- | Extract all example @(CSV, generatedCode)@ pairs from
-- @test/examples.toml@
csvTests :: [(CsvExample, String)]
csvTests = $(do addDependentFile "test/examples.toml"
                csvExamples <- TH.runIO (examplesFrom "test/examples.toml")
                ListE <$> mapM (\x@(CsvExample _ c _) -> 
                                  [e|(x,$(generateCode "Row" c))|])
                               csvExamples)

-- | Detect type-compatible re-used names and do not attempt to
-- re-generate definitions for them. This does not do the right thing
-- since the generated declarations are never turned into actual
-- declarations, they do not affect the `lookupTypeName` call that is
-- designed to prevent duplicate declarations.
overlappingGeneration :: String
overlappingGeneration = m ++ "\n\n" ++ e
  where m = $(do csvExamples <- TH.runIO (examplesFrom "test/examples.toml")
                 let Just (CsvExample _ managers _) = 
                       find (\(CsvExample k _ _) -> k == "managers") csvExamples
                 generateCode "ManagerRec" managers)
        e = $(do csvExamples <- TH.runIO (examplesFrom "test/examples.toml")
                 let Just (CsvExample _ employees _) = 
                       find (\(CsvExample k _ _) -> k == "employees") csvExamples
                 generateCode "EmployeeRec" employees)

-- | To generate example generated code from raw CSV data, add the csv
-- to @examples.toml@ and set the @generated@ key to an empty
-- string. Then load this file into a REPL that has @:set
-- -XTemplateHaskell@ and evaluate @putStrLn $(manualGeneration
-- "employees")@, for example.
-- 
-- Note that to load this file into a REPL may require some fiddling
-- with the path to the examples file in the 'csvTests' splice above.
manualGeneration :: String -> Q Exp
manualGeneration k = do csvExamples <- TH.runIO (examplesFrom "test/examples.toml")
                        maybe (error ("Table " ++ k ++ " not found")) 
                              (generateCode "Row") 
                              (getFirst $ foldMap aux csvExamples)
  where aux :: CsvExample -> First String
        aux (CsvExample k' c _) = if k == k' then pure c else mempty

main :: IO ()
main = do
  hspec $
    do describe "Haskell type generation" $ 
         mapM_ (\(CsvExample k _ g, g') -> it k (g' `shouldBe` g)) csvTests
       describe "Multiple tables" $
          do g <- H.runIO $ 
                  generatedFrom "test/examples.toml" "managers_employees"
             it "Shouldn't duplicate columns" pending