Compare commits

...

7 commits

19 changed files with 238 additions and 239 deletions

3
.gitignore vendored
View file

@ -1,2 +1,5 @@
/dist-newstyle/* /dist-newstyle/*
.ghc.environment.* .ghc.environment.*
*.o
*.hi
Main

View file

@ -62,6 +62,18 @@ mkdir -p ~/.sjw
cp -r src/ ~/.sjw/unitJS cp -r src/ ~/.sjw/unitJS
``` ```
Then, the static data used by hablo need to be available in a XDG path. Depending on whether you are installing for your user or system-wide, you may want to perform something either
```bash
cp -R share ~/.local/share/hablo
```
or
```bash
sudo cp -R share /usr/local/share/hablo
```
### Using hablo (tutorials) ### Using hablo (tutorials)
Wanna give it a try ? Start by [generating your blog](https://git.marvid.fr/Tissevert/hablo/wiki/Generating%20your%20blog) Wanna give it a try ? Start by [generating your blog](https://git.marvid.fr/Tissevert/hablo/wiki/Generating%20your%20blog)

View file

@ -1,11 +1,7 @@
(use-modules (gnu packages haskell-xyz) (use-modules ((guix build-system haskell) #:select (hackage-uri haskell-build-system))
(gnu packages haskell-web) ((guix download) #:select (url-fetch))
(guix build-system haskell) ((guix licenses) #:select (bsd-3))
(guix download) ((guix packages) #:select (base32 origin package)))
(guix gexp)
(guix git-download)
(guix licenses)
(guix packages))
(package (package
(name "ghc-template") (name "ghc-template")

View file

@ -1,4 +1,5 @@
(use-modules (gnu packages haskell-xyz) (use-modules (gnu packages haskell-check)
(gnu packages haskell-xyz)
(gnu packages haskell-web) (gnu packages haskell-web)
(guix build-system haskell) (guix build-system haskell)
(guix download) (guix download)
@ -19,9 +20,11 @@
#:recursive? #t #:recursive? #t
#:select? (git-predicate %source-dir))) #:select? (git-predicate %source-dir)))
(build-system haskell-build-system) (build-system haskell-build-system)
(propagated-inputs (list sjw-unitjs))
(inputs (inputs
(list ghc-aeson (list ghc-aeson
ghc-attoparsec ghc-attoparsec
ghc-hunit
ghc-lucid ghc-lucid
ghc-optparse-applicative ghc-optparse-applicative
ghc-parsec ghc-parsec
@ -29,10 +32,19 @@
ghc-sjw ghc-sjw
ghc-template ghc-template
ghc-xdg-basedir)) ghc-xdg-basedir))
(arguments
`(#:phases
(modify-phases %standard-phases
(add-after 'install 'copy-static-resources
(lambda* (#:key outputs #:allow-other-keys)
(let ((out (assoc-ref outputs "out")))
(copy-recursively "share" (string-append out "/share/hablo"))))))))
(native-search-paths (native-search-paths
(list (list
(search-path-specification (variable "SJW_PATH") (search-path-specification (variable "SJW_PATH")
(files '("lib/SJW"))))) (files '("lib/SJW")))
(search-path-specification (variable "XDG_DATA_DIRS")
(files '("share")))))
(home-page "https://git.marvid.fr/Tissevert/SJW") (home-page "https://git.marvid.fr/Tissevert/SJW")
(synopsis "The Simple Javascript Wrench") (synopsis "The Simple Javascript Wrench")
(description (description

View file

@ -23,9 +23,6 @@ maintainer: tissevert+devel@marvid.fr
category: Web category: Web
extra-source-files: CHANGELOG.md extra-source-files: CHANGELOG.md
build-type: Simple build-type: Simple
data-dir: share
data-files: js/*.js
defaultWording.conf
library library
exposed-modules: Arguments exposed-modules: Arguments
@ -46,7 +43,6 @@ library
, JSON , JSON
, Markdown , Markdown
, Page , Page
, Paths_hablo
, Pretty , Pretty
, RSS , RSS
-- other-extensions: -- other-extensions:
@ -65,13 +61,13 @@ library
, time >= 1.8.0 && < 1.12 , time >= 1.8.0 && < 1.12
, SJW >= 0.1.2 && < 0.2 , SJW >= 0.1.2 && < 0.2
, unix >= 2.7.2 && < 2.8 , unix >= 2.7.2 && < 2.8
, xdg-basedir >= 0.2.2 && < 0.3
ghc-options: -Wall ghc-options: -Wall
hs-source-dirs: src hs-source-dirs: src
default-language: Haskell2010 default-language: Haskell2010
executable hablo executable hablo
main-is: src/Main.hs main-is: src/Main.hs
other-modules: Paths_hablo
-- other-extensions: -- other-extensions:
build-depends: base build-depends: base
, hablo , hablo
@ -80,8 +76,8 @@ executable hablo
default-language: Haskell2010 default-language: Haskell2010
test-suite tests test-suite tests
type: detailed-0.9 type: exitcode-stdio-1.0
test-module: Tests main-is: Main.hs
other-modules: Mock.Arguments other-modules: Mock.Arguments
, Mock.Article , Mock.Article
, Mock.ArticlesList , Mock.ArticlesList
@ -99,11 +95,11 @@ test-suite tests
, XML.Card.Component , XML.Card.Component
, XML.Card.Output , XML.Card.Output
build-depends: base build-depends: base
, Cabal
, containers , containers
, directory , directory
, filepath , filepath
, hablo , hablo
, HUnit
, lucid , lucid
, mtl , mtl
, text , text

View file

@ -2,22 +2,23 @@
module Arguments ( module Arguments (
Arguments(..) Arguments(..)
, get , get
, version
) where ) where
#if !MIN_VERSION_base(4,11,0) #if !MIN_VERSION_base(4,11,0)
import Data.Monoid ((<>)) import Data.Monoid ((<>))
#endif #endif
import Data.Version (showVersion) import Control.Applicative ((<**>), optional)
import Control.Applicative ((<|>), (<**>), optional) import Options.Applicative
import Options.Applicative ( ( Parser, ReadM, argument, auto, eitherReader, execParser, fullDesc, header
Parser, ReadM, argument, auto, eitherReader, execParser, flag', fullDesc , help, helper, info, infoOption, long, metavar, short, str, switch, value )
, header, help, helper, info, long, metavar, short, str, switch, value
)
import qualified Options.Applicative as Optparse (option) import qualified Options.Applicative as Optparse (option)
import qualified Paths_hablo as Hablo (version)
import System.FilePath (dropTrailingPathSeparator, isValid) import System.FilePath (dropTrailingPathSeparator, isValid)
data Arguments = BlogConfig { version :: String
version = "0.3.0.0"
data Arguments = Arguments {
sourceDir :: FilePath sourceDir :: FilePath
, articlesPath :: Maybe FilePath , articlesPath :: Maybe FilePath
, bannerPath :: Maybe FilePath , bannerPath :: Maybe FilePath
@ -35,7 +36,6 @@ data Arguments = BlogConfig {
, siteURL :: Maybe String , siteURL :: Maybe String
, wording :: Maybe FilePath , wording :: Maybe FilePath
} }
| Version
option :: ReadM a -> Char -> String -> String -> String -> Parser (Maybe a) option :: ReadM a -> Char -> String -> String -> String -> Parser (Maybe a)
option readM aShort aLong aMetavar aHelpMessage = option readM aShort aLong aMetavar aHelpMessage =
@ -47,8 +47,8 @@ option readM aShort aLong aMetavar aHelpMessage =
<> help aHelpMessage <> help aHelpMessage
) )
blogConfig :: Parser Arguments arguments :: Parser Arguments
blogConfig = BlogConfig arguments = Arguments
<$> argument filePath (value "." <> metavar "INPUT_DIR") <$> argument filePath (value "." <> metavar "INPUT_DIR")
<*> option filePath 'a' "articles" "DIRECTORY" <*> option filePath 'a' "articles" "DIRECTORY"
"relative path to the directory containing the articles within INPUT_DIR" "relative path to the directory containing the articles within INPUT_DIR"
@ -81,16 +81,6 @@ blogConfig = BlogConfig
<*> option filePath 'u' "site-url" "URL" "URL where the blog is published" <*> option filePath 'u' "site-url" "URL" "URL where the blog is published"
<*> option filePath 'w' "wording" "FILE" "path to the file containing the wording to use" <*> option filePath 'w' "wording" "FILE" "path to the file containing the wording to use"
version :: Parser Arguments
version = flag' Version (
long "version"
<> short 'v'
<> help "print the version number"
)
arguments :: Parser Arguments
arguments = blogConfig <|> version
filePath :: ReadM FilePath filePath :: ReadM FilePath
filePath = eitherReader $ \path -> filePath = eitherReader $ \path ->
if isValid path if isValid path
@ -98,8 +88,10 @@ filePath = eitherReader $ \path ->
else Left "This string doesn't represent a valid path" else Left "This string doesn't represent a valid path"
get :: IO Arguments get :: IO Arguments
get = do get = execParser
execParser $ (info (arguments <**> showVersion <**> helper)
info (fullDesc <> header ("Hablo v" ++ version)))
(arguments <**> helper) where
(fullDesc <> header ("Hablo v" ++ showVersion Hablo.version)) showVersion = infoOption
version
(long "version" <> short 'v' <> help "print current version")

View file

@ -12,7 +12,7 @@ import Data.Map (Map)
import qualified Data.Map as Map (empty, fromList, keys, map, union) import qualified Data.Map as Map (empty, fromList, keys, map, union)
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as Text (pack) import qualified Data.Text as Text (pack)
import Paths_hablo (getDataFileName) import Files (getXDGData)
import Text.ParserCombinators.Parsec ( import Text.ParserCombinators.Parsec (
Parser Parser
, (<|>) , (<|>)
@ -64,6 +64,6 @@ wordingP = Map.map Text.pack . Map.fromList <$>
build :: Arguments -> IO Wording build :: Arguments -> IO Wording
build arguments = do build arguments = do
defaultWording <- getDataFileName "defaultWording.conf" defaultWording <- getXDGData "defaultWording.conf"
let wordingFiles = maybe id (:) (wording arguments) $ [defaultWording] let wordingFiles = maybe id (:) (wording arguments) $ [defaultWording]
Wording <$> foldM addWording Map.empty wordingFiles Wording <$> foldM addWording Map.empty wordingFiles

View file

@ -3,9 +3,12 @@ module Files (
, absoluteLink , absoluteLink
, filePath , filePath
, find , find
, getXDGData
) where ) where
import System.Directory (doesDirectoryExist, doesFileExist, listDirectory) import System.Directory (doesDirectoryExist, doesFileExist, doesPathExist, listDirectory)
import System.Environment.XDG.BaseDir (getAllDataDirs)
import System.Exit (die)
import System.FilePath ((</>)) import System.FilePath ((</>))
data File = File FilePath | Dir FilePath data File = File FilePath | Dir FilePath
@ -30,3 +33,14 @@ find path =
filePath (Dir path) >>= emptyIfMissing (fmap ((path </>) <$>) . listDirectory) filePath (Dir path) >>= emptyIfMissing (fmap ((path </>) <$>) . listDirectory)
where where
emptyIfMissing = either (\_ -> return []) emptyIfMissing = either (\_ -> return [])
getXDGData :: FilePath -> IO FilePath
getXDGData resource = getAllDataDirs relativePath >>= findFirst
where
relativePath = "hablo" </> resource
findFirst [] = die ("Install is broken: "
<> relativePath
<> " directory wasn't found in any of $XDG_DATA_DIRS")
findFirst (path:paths) = do
fileExists <- doesPathExist path
if fileExists then pure path else findFirst paths

View file

@ -13,8 +13,8 @@ import Data.ByteString.Lazy (
) )
import Data.ByteString.Lazy.Char8 (pack) import Data.ByteString.Lazy.Char8 (pack)
import Data.Text.Encoding (encodeUtf8) import Data.Text.Encoding (encodeUtf8)
import Files (getXDGData)
import JSON (exportBlog) import JSON (exportBlog)
import Paths_hablo (getDataDir)
import Pretty ((.$)) import Pretty ((.$))
import SJW (compile, source) import SJW (compile, source)
import System.Directory (createDirectoryIfMissing) import System.Directory (createDirectoryIfMissing)
@ -44,7 +44,7 @@ generateConfig destinationDir = do
generateMain :: FilePath -> IO () generateMain :: FilePath -> IO ()
generateMain destinationDir = do generateMain destinationDir = do
habloSources <- (</> "js") <$> getDataDir habloSources <- getXDGData "js"
compile (source [destinationDir, "unitJS", habloSources]) compile (source [destinationDir, "unitJS", habloSources])
>>= either abort (output . fst) >>= either abort (output . fst)
where where

View file

@ -1,23 +1,16 @@
module Main where module Main where
import Arguments (Arguments(..)) import Arguments (Arguments(..), version)
import qualified Arguments (get) import qualified Arguments (get)
import qualified Blog (build) import qualified Blog (build)
import Control.Monad.Reader (runReaderT) import Control.Monad.Reader (runReaderT)
import Data.Version (showVersion)
import qualified HTML (generate) import qualified HTML (generate)
import qualified JS (generate) import qualified JS (generate)
import qualified Paths_hablo as Hablo (version)
import qualified RSS (generate) import qualified RSS (generate)
import System.Exit (exitSuccess) import System.Exit (exitSuccess)
main :: IO () main :: IO ()
main = do main = Arguments.get >>= Blog.build >>= runReaderT
arguments <- Arguments.get (do HTML.generate
case arguments of JS.generate
Version -> (putStrLn $ showVersion Hablo.version) >> exitSuccess RSS.generate)
config@(BlogConfig {}) -> Blog.build config >>= runReaderT (do
HTML.generate
JS.generate
RSS.generate
)

View file

@ -1,3 +1,6 @@
pre { - dans Arguments.hs, vérifier que l'implémentation de option est pas déjà dans la lib optparse-applicative
white-space: pre-wrap; => ah non en fait c'est une fonction locale au fichier juste mal nommée, corriger ça
} - le Wording, c'était quand même pas l'idée du siècle -> ça pourrait pas tout revenir dans un thème qui serait du HTML ?
- faque Template aussi
- «Pretty» Oo ? mais c'est juste des Utils en fait
- améliorer un peu la gestion des erreurs ? (ExceptT IO…) pas prio mais ça nuirait pas

10
test/Main.hs Normal file
View file

@ -0,0 +1,10 @@
module Main where
import qualified Structure (test)
import Test.HUnit (Test(..), runTestTTAndExit)
import qualified XML.Card (test)
main :: IO ()
main = runTestTTAndExit $ TestList
[ XML.Card.test
, Structure.test ]

View file

@ -16,7 +16,7 @@ import Arguments (Arguments(..))
import Utils (testDataPath) import Utils (testDataPath)
defaultArticles :: Arguments defaultArticles :: Arguments
defaultArticles = BlogConfig { defaultArticles = Arguments {
sourceDir = testDataPath "Structure/defaultArticles" sourceDir = testDataPath "Structure/defaultArticles"
, articlesPath = Nothing , articlesPath = Nothing
, bannerPath = Nothing , bannerPath = Nothing

View file

@ -5,36 +5,37 @@ module Structure (
import Arguments (Arguments(..)) import Arguments (Arguments(..))
import Blog (Path) import Blog (Path)
import qualified Blog.Path as Path (build) import qualified Blog.Path as Path (build)
import Distribution.TestSuite
import qualified Mock.Arguments as Arguments import qualified Mock.Arguments as Arguments
import qualified Mock.Blog.Path as Path import qualified Mock.Blog.Path as Path
import System.Directory (withCurrentDirectory) import System.Directory (withCurrentDirectory)
import Utils (simpleTest, tag) import Test.HUnit (Test(..), assertEqual)
import Utils (labeled, testGroup)
checkPath :: Arguments -> Maybe Path -> IO Progress checkPath :: Arguments -> Maybe Path -> Test
checkPath input expected = do checkPath input expected = TestCase . withCurrentDirectory root $
withCurrentDirectory root $ do either (\_ -> Nothing) Just <$> Path.build root input
actual <- either (\_ -> Nothing) Just <$> Path.build root input >>= assertEqual "Incorrect path detected by hablo" expected
return . Finished $
if actual == expected
then Pass
else Fail $ "Expected " ++ show expected ++ " but got " ++ show actual
where where
root = sourceDir input root = sourceDir input
test :: Test test :: Test
test = tag "structure" . testGroup "Blog structure" $ simpleTest <$> [ test = testGroup "Blog structure" $ labeled
("empty structure", checkPath Arguments.emptyBlog Nothing) [ ("empty structure", checkPath Arguments.emptyBlog Nothing)
, ("default articles", checkPath Arguments.defaultArticles $ Just Path.defaultArticles) , ("default articles"
, ("default pages", checkPath Arguments.defaultPages $ Just Path.defaultPages) , checkPath Arguments.defaultArticles $ Just Path.defaultArticles)
, ("both default", checkPath Arguments.bothDefault $ Just Path.bothDefault) , ("default pages", checkPath Arguments.defaultPages $ Just Path.defaultPages)
, ("custom articles", checkPath Arguments.customArticles $ Just Path.customArticles) , ("both default", checkPath Arguments.bothDefault $ Just Path.bothDefault)
, ("custom pages", checkPath Arguments.customPages $ Just Path.customPages) , ("custom articles"
, ("both custom", checkPath Arguments.bothCustom $ Just Path.bothCustom) , checkPath Arguments.customArticles $ Just Path.customArticles)
, ("custom articles, default pages" , ("custom pages", checkPath Arguments.customPages $ Just Path.customPages)
, checkPath Arguments.customArticlesDefaultPages $ Just Path.customArticlesDefaultPages) , ("both custom", checkPath Arguments.bothCustom $ Just Path.bothCustom)
, ("custom pages, default articles" , ("custom articles, default pages"
, checkPath Arguments.customPagesDefaultArticles $ Just Path.customPagesDefaultArticles) , (checkPath
, ("bad custom articles", checkPath Arguments.badCustomArticles $ Nothing) Arguments.customArticlesDefaultPages
, ("bad custom pages", checkPath Arguments.badCustomPages $ Nothing) (Just Path.customArticlesDefaultPages)))
] , ("custom pages, default articles"
, (checkPath
Arguments.customPagesDefaultArticles
(Just Path.customPagesDefaultArticles)))
, ("bad custom articles", checkPath Arguments.badCustomArticles $ Nothing)
, ("bad custom pages", checkPath Arguments.badCustomPages $ Nothing) ]

View file

@ -1,14 +0,0 @@
module Tests (
tests
) where
import Distribution.TestSuite
import qualified Structure (test)
import Utils (tag)
import qualified XML.Card (test)
tests :: IO [Test]
tests = return $ tag "xml" <$> [
XML.Card.test
, Structure.test
]

View file

@ -1,49 +1,17 @@
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
module Utils ( module Utils
assertAll ( labeled
, assertEqual , testDataPath
, simpleTest , testGroup ) where
, tag
, testDataPath
) where
import Distribution.TestSuite
import System.FilePath ((</>)) import System.FilePath ((</>))
import Text.Printf (printf) import Test.HUnit (Test(..))
tagInstance :: String -> TestInstance -> TestInstance
tagInstance tagName testInstance = testInstance {
tags = tagName : (tags testInstance)
}
tag :: String -> Test -> Test
tag tagName (Test testInstance) = Test (tagInstance tagName testInstance)
tag tagName group = group {groupTests = tag tagName <$> groupTests group}
simpleTest :: (String, IO Progress) -> Test
simpleTest (name, run) = Test testInstance
where
testInstance = TestInstance {
run
, name
, tags = []
, options = []
, setOption = \_ _ -> Right testInstance
}
wrong :: Show a => String -> a -> a -> IO Progress
wrong message expected actual = return . Finished . Fail $
printf "%s: %s vs. %s" message (show expected) (show actual)
assertAll :: [(Bool, IO Progress, String)] -> IO Progress
assertAll = foldr assert (return $ Finished Pass)
where
assert (bool, badIssue, checkMessage) next =
if bool then return $ Progress checkMessage next else badIssue
assertEqual :: (Show a, Eq a) => String -> a -> a -> (Bool, IO Progress, String)
assertEqual what a b =
(a == b, wrong (what ++ " do not match !") a b, what ++ " ok")
testDataPath :: FilePath -> FilePath testDataPath :: FilePath -> FilePath
testDataPath = ("test" </>) testDataPath = ("test" </>)
testGroup :: String -> [Test] -> Test
testGroup name = TestLabel name . TestList
labeled :: [(String, Test)] -> [Test]
labeled = fmap (uncurry TestLabel)

View file

@ -2,10 +2,10 @@ module XML.Card (
test test
) where ) where
import Distribution.TestSuite import Test.HUnit (Test)
import Utils (tag) import Utils (testGroup)
import qualified XML.Card.Component as Component (test) import qualified XML.Card.Component as Component (test)
import qualified XML.Card.Output as Output (test) import qualified XML.Card.Output as Output (test)
test :: Test test :: Test
test = tag "card" $ testGroup "Cards" [Component.test, Output.test] test = testGroup "Cards" [Component.test, Output.test]

View file

@ -7,83 +7,84 @@ import Blog (Blog)
import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.Reader (runReaderT) import Control.Monad.Reader (runReaderT)
import Data.Text (Text) import Data.Text (Text)
import Distribution.TestSuite
import DOM.Card (HasCard(..)) import DOM.Card (HasCard(..))
import Mock.Blog as Blog (simple) import Mock.Blog as Blog (simple)
import Mock.Article as Article (noDescription, noImage, simple) import Mock.Article as Article (noDescription, noImage, simple)
import Mock.ArticlesList as ArticlesList ( import Mock.ArticlesList as ArticlesList (
longMain, longTesting, shortMain, shortTesting longMain, longTesting, shortMain, shortTesting
) )
import Utils (assertAll, assertEqual, simpleTest, tag) import Test.HUnit (Test(..), assertEqual)
import Utils (labeled, testGroup)
check :: HasCard a => IO Blog -> a -> (Text, Text, Maybe String, String, String) -> IO Progress check :: HasCard a => IO Blog -> a -> (Text, Text, Maybe String, String, String) -> IO ()
check getBlog input (expectedCT, expectedD, expectedI, expectedT, expectedU) = check getBlog input (expectedCT, expectedD, expectedI, expectedT, expectedU) =
getBlog >>= runReaderT ( getBlog >>= runReaderT checkCard
sequence [ where
assertEqual "card types" expectedCT <$> cardType input checkCard = do
, assertEqual "descriptions" expectedD <$> description input liftIO . assertEqual "card types" expectedCT =<< cardType input
, assertEqual "images" expectedI <$> image input liftIO . assertEqual "descriptions" expectedD =<< description input
, assertEqual "titles" expectedT <$> title input liftIO . assertEqual "images" expectedI =<< image input
, assertEqual "urls" expectedU <$> urlPath input liftIO . assertEqual "titles" expectedT =<< title input
] >>= liftIO . assertAll liftIO . assertEqual "urls" expectedU =<< urlPath input
)
articleCard :: Test articleCard :: Test
articleCard = tag "article" . testGroup "Article cards" $ simpleTest <$> [ articleCard = testGroup "Article cards" $ labeled
("simple article components", check Blog.simple Article.simple ( [ ("simple article components"
"article" , TestCase $ check Blog.simple Article.simple
, "It's a test" ( "article"
, Just "test.png" , "It's a test"
, "Some test" , Just "test.png"
, "articles/test.html" , "Some test"
)) , "articles/test.html" ))
, ("article components without description", check Blog.simple Article.noDescription ( , ("article components without description"
"article" , TestCase $ check Blog.simple Article.noDescription
, "A new article on The Test Blog" ( "article"
, Just "test.png" , "A new article on The Test Blog"
, "Some test" , Just "test.png"
, "articles/test.html" , "Some test"
)) , "articles/test.html" ))
, ("article components without image", check Blog.simple Article.noImage ( , ("article components without image"
"article" , TestCase $ check Blog.simple Article.noImage
, "It's a test" ( "article"
, Nothing , "It's a test"
, "Some test" , Nothing
, "articles/test.html" , "Some test"
)) , "articles/test.html" )) ]
]
articlesListCard :: Test articlesListCard :: Test
articlesListCard = tag "articlesList" . testGroup "Articles list cards" $ simpleTest <$> [ articlesListCard = testGroup "Articles list cards" $ labeled
("short untagged page component", ArticlesList.shortMain >>= (flip (check Blog.simple) ( [ ("short untagged page component"
"website" , TestCase (ArticlesList.shortMain >>=
, "Latest articles" (flip (check Blog.simple)
, Nothing ( "website"
, "The Test Blog" , "Latest articles"
, "index.html" , Nothing
))) , "The Test Blog"
, ("long untagged page component", ArticlesList.longMain >>= (flip (check Blog.simple) ( , "index.html"))))
"website" , ("long untagged page component"
, "All articles" , TestCase (ArticlesList.longMain >>=
, Nothing (flip (check Blog.simple)
, "The Test Blog" ( "website"
, "all.html" , "All articles"
))) , Nothing
, ("short tagged page component", ArticlesList.shortTesting >>= (flip (check Blog.simple) ( , "The Test Blog"
"website" , "all.html"))))
, "Latest articles tagged testing" , ("short tagged page component"
, Nothing , TestCase (ArticlesList.shortTesting >>=
, "The Test Blog - testing" (flip (check Blog.simple)
, "testing/index.html" ( "website"
))) , "Latest articles tagged testing"
, ("long tagged page component", ArticlesList.longTesting >>= (flip (check Blog.simple) ( , Nothing
"website" , "The Test Blog - testing"
, "All articles tagged testing" , "testing/index.html"))))
, Nothing , ("long tagged page component"
, "The Test Blog - testing" , TestCase (ArticlesList.longTesting >>=
, "testing/all.html" (flip (check Blog.simple)
))) ( "website"
] , "All articles tagged testing"
, Nothing
, "The Test Blog - testing"
, "testing/all.html")))) ]
test :: Test test :: Test
test = tag "component" $ testGroup "Cards components" [articleCard, articlesListCard] test = testGroup "Cards components" [articleCard, articlesListCard]

View file

@ -6,7 +6,6 @@ import Blog (Blog(..), URL(..))
import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.Reader (asks, runReaderT) import Control.Monad.Reader (asks, runReaderT)
import qualified Data.Text.Lazy.IO as Lazy (readFile) import qualified Data.Text.Lazy.IO as Lazy (readFile)
import Distribution.TestSuite
import DOM.Card (HasCard(..), make) import DOM.Card (HasCard(..), make)
import Lucid (renderTextT) import Lucid (renderTextT)
import Mock.Blog as Blog (noCards, simple) import Mock.Blog as Blog (noCards, simple)
@ -16,34 +15,47 @@ import Mock.ArticlesList as ArticlesList (
) )
import Pretty ((.$)) import Pretty ((.$))
import System.FilePath ((</>)) import System.FilePath ((</>))
import Utils (assertAll, assertEqual, simpleTest, tag, testDataPath) import Test.HUnit (Test(..), assertEqual)
import Utils (labeled, testDataPath, testGroup)
check :: HasCard a => IO Blog -> a -> FilePath -> IO Progress check :: HasCard a => IO Blog -> a -> FilePath -> IO ()
check getBlog input expectedFile = check getBlog input expectedFile = getBlog >>= runReaderT checkHTML
getBlog >>= runReaderT (do where
checkHTML = do
actual <- renderTextT $ maybe (return ()) (DOM.Card.make input) =<< (asks $urls.$cards) actual <- renderTextT $ maybe (return ()) (DOM.Card.make input) =<< (asks $urls.$cards)
expected <- liftIO . Lazy.readFile $ testDataPath "XML/Card/Output" </> expectedFile expected <- liftIO . Lazy.readFile $ testDataPath "XML/Card/Output" </> expectedFile
liftIO $ assertAll [ liftIO $ assertEqual "card HTML output" expected actual
assertEqual "card HTML output" expected actual
]
)
articleCard :: Test articleCard :: Test
articleCard = tag "article" . testGroup "Article cards" $ simpleTest <$> [ articleCard = testGroup "Article cards" $ labeled
("simple article output", check Blog.simple Article.simple "simple.html") [ ("simple article output"
, ("article output without description", check Blog.simple Article.noDescription "noDescription.html") , TestCase $ check Blog.simple Article.simple "simple.html")
, ("article output without image", check Blog.simple Article.noImage "noImage.html") , ("article output without description"
, ("no card article output", check Blog.noCards Article.simple "/dev/null") , TestCase $ check Blog.simple Article.noDescription "noDescription.html")
] , ("article output without image"
, TestCase $ check Blog.simple Article.noImage "noImage.html")
, ("no card article output"
, TestCase $ check Blog.noCards Article.simple "/dev/null") ]
articlesListCard :: Test articlesListCard :: Test
articlesListCard = tag "article" . testGroup "Article cards" $ simpleTest <$> [ articlesListCard = testGroup "Article list cards" $ labeled
("short untagged page output", ArticlesList.shortMain >>= flip (check Blog.simple) "shortMain.html") [ ("short untagged page output"
, ("long untagged page output", ArticlesList.longMain >>= flip (check Blog.simple) "longMain.html") , TestCase
, ("short tagged page output", ArticlesList.shortTesting >>= flip (check Blog.simple) "shortTesting.html") (ArticlesList.shortMain >>= flip (check Blog.simple) "shortMain.html"))
, ("long tagged page output", ArticlesList.longTesting >>= flip (check Blog.simple) "longTesting.html") , ("long untagged page output"
, ("no card articlesList output", ArticlesList.shortMain >>= flip (check Blog.noCards) "/dev/null") , TestCase
] (ArticlesList.longMain >>= flip (check Blog.simple) "longMain.html"))
, ("short tagged page output"
, TestCase
(ArticlesList.shortTesting
>>= flip (check Blog.simple) "shortTesting.html"))
, ("long tagged page output"
, TestCase
(ArticlesList.longTesting
>>= flip (check Blog.simple) "longTesting.html"))
, ("no card articlesList output"
, TestCase
(ArticlesList.shortMain >>= flip (check Blog.noCards) "/dev/null")) ]
test :: Test test :: Test
test = tag "output" $ testGroup "Cards outputs" [articleCard, articlesListCard] test = testGroup "Cards outputs" [articleCard, articlesListCard]