gitson-0.5.2: test-suite/GitsonSpec.hs
{-# LANGUAGE TemplateHaskell, UnicodeSyntax #-}
module GitsonSpec (spec) where
import Test.Hspec
import System.Directory
import Data.Aeson.TH
import Data.List (sort)
import Control.Exception
import Control.Monad.IO.Class
import Control.Monad (void)
import Gitson
import Gitson.Util (insideDirectory, lastCommitText)
{-# ANN module ("HLint: ignore Redundant do" :: String) #-}
data Thing = Thing { val ∷ Int } deriving (Eq, Show, Ord)
$(deriveJSON defaultOptions ''Thing)
spec ∷ Spec
spec = before setup $ after cleanup $ do
context "transaction" $ do
describe "saveDocument" $ do
it "saves entries only after it's done" $ do
transaction "tmp/repo" $ do
saveDocument "things" "first-thing" Thing {val = 1}
saveDocument "things" "second-thing" Thing {val = 2}
liftIO $ readFile "things/first-thing.json" `shouldThrow` anyIOException
liftIO $ readFile "things/second-thing.json" `shouldThrow` anyIOException
insideDirectory "tmp/repo" $ do
first ← readFile "things/first-thing.json"
first `shouldBe` "{\n \"val\": 1.0\n}"
second ← readFile "things/second-thing.json"
second `shouldBe` "{\n \"val\": 2.0\n}"
commitMsg ← lastCommitText
commitMsg `shouldBe` "Gitson transaction"
describe "saveNextDocument" $ do
it "saves entries with next numeric ids" $ do
transaction "tmp/repo" $ do
saveNextDocument "things" "hello" Thing {val = 1}
saveNextDocument "things" "world" Thing {val = 2}
insideDirectory "tmp/repo" $ do
first ← readFile "things/000001-hello.json"
first `shouldBe` "{\n \"val\": 1.0\n}"
second ← readFile "things/000002-world.json"
second `shouldBe` "{\n \"val\": 2.0\n}"
describe "saveDocumentById" $ do
it "updates an entry by specified id" $ do
createDirectoryIfMissing True "tmp/repo/things"
_ ← liftIO $ writeFile "tmp/repo/things/000004-second-thing.json" "{\"val\":1}"
transaction "tmp/repo" $ do
saveDocumentById "things" 4 Thing {val = 2}
insideDirectory "tmp/repo" $ do
second ← readFile "things/000004-second-thing.json"
second `shouldBe` "{\n \"val\": 2.0\n}"
describe "saveDocumentByName" $ do
it "updates an entry by specified name" $ do
createDirectoryIfMissing True "tmp/repo/things"
_ ← liftIO $ writeFile "tmp/repo/things/000004-second-thing.json" "{\"val\":1}"
transaction "tmp/repo" $ do
saveDocumentByName "things" "second-thing" Thing {val = 2}
insideDirectory "tmp/repo" $ do
second ← readFile "things/000004-second-thing.json"
second `shouldBe` "{\n \"val\": 2.0\n}"
describe "readDocument" $ do
it "returns Just the document when reading an document by key" $ do
createDirectoryIfMissing True "tmp/repo/things"
_ ← writeFile "tmp/repo/things/second-thing.json" "{\"val\":2}"
content ← readDocument "tmp/repo/things" "second-thing" ∷ IO (Maybe Thing)
content `shouldBe` Just Thing {val = 2}
it "returns Nothing when reading by a nonexistent key" $ do
content ← readDocument "tmp/repo/things" "totally-not-a-thing" ∷ IO (Maybe Thing)
content `shouldBe` Nothing
describe "readDocumentById" $ do
it "returns Just the document when reading an document by id" $ do
createDirectoryIfMissing True "tmp/repo/things"
_ ← writeFile "tmp/repo/things/000004-second-thing.json" "{\"val\":1}"
content ← readDocumentById "tmp/repo/things" 4 ∷ IO (Maybe Thing)
content `shouldBe` Just Thing {val = 1}
it "returns Nothing when reading by a nonexistent id" $ do
content ← readDocumentById "tmp/repo/things" 1 ∷ IO (Maybe Thing)
content `shouldBe` Nothing
describe "readDocumentByName" $ do
it "returns Just the document when reading an document by name" $ do
createDirectoryIfMissing True "tmp/repo/things"
_ ← writeFile "tmp/repo/things/000098-second-thing.json" "{\"val\":1}"
content ← readDocumentByName "tmp/repo/things" "second-thing" ∷ IO (Maybe Thing)
content `shouldBe` Just Thing {val = 1}
it "returns Nothing when reading by a nonexistent name" $ do
content ← readDocumentByName "tmp/repo/things" "yolo" ∷ IO (Maybe Thing)
content `shouldBe` Nothing
describe "documentIdFromName" $ do
it "returns Just the document id from the document's name" $ do
createDirectoryIfMissing True "tmp/repo/things"
_ ← writeFile "tmp/repo/things/000098-some-thing.json" "THIS SHOULD NOT BE READ"
i ← documentIdFromName "tmp/repo/things" "some-thing"
i `shouldBe` Just 98
it "returns Nothing when run with a nonexistent name" $ do
i ← documentIdFromName "tmp/repo/things" "yolo"
i `shouldBe` Nothing
describe "documentNameFromId" $ do
it "returns Just the document name from the document's id" $ do
createDirectoryIfMissing True "tmp/repo/things"
_ ← writeFile "tmp/repo/things/000098-some-thing.json" "THIS SHOULD NOT BE READ"
i ← documentNameFromId "tmp/repo/things" 98
i `shouldBe` Just "some-thing"
it "returns Nothing when run with a nonexistent id" $ do
i ← documentNameFromId "tmp/repo/things" 123
i `shouldBe` Nothing
describe "listDocumentKeys" $ do
it "returns a list of document keys when listing a collection" $ do
createDirectoryIfMissing True "tmp/repo/things"
_ ← writeFile "tmp/repo/things/first-thing.json" "{}"
_ ← writeFile "tmp/repo/things/second-thing.json" "{}"
list ← listDocumentKeys "tmp/repo/things"
sort list `shouldBe` ["first-thing", "second-thing"]
it "returns an empty when listing a nonexistent collection" $ do
list ← listDocumentKeys "nonsense"
list `shouldBe` []
describe "listEntries" $ do
it "returns a list of entries when listing a collection" $ do
createDirectoryIfMissing True "tmp/repo/things"
_ ← writeFile "tmp/repo/things/first-thing.json" "{\"val\":1}"
_ ← writeFile "tmp/repo/things/second-thing.json" "{\"val\":2}"
list ← listEntries "tmp/repo/things" ∷ IO [Thing]
sort list `shouldBe` [Thing {val = 1}, Thing {val = 2}]
it "returns an empty list when listing a nonexistent collection" $ do
list ← listEntries "nonsense" ∷ IO [Thing]
list `shouldBe` []
describe "listCollections" $ do
it "returns a list of collections" $ do
createDirectoryIfMissing True "tmp/repo/bits"
createDirectoryIfMissing True "tmp/repo/pieces"
insideDirectory "tmp/repo" $ do
list ← listCollections
sort list `shouldBe` ["bits", "pieces"]
it "returns an empty list when listing an empty repo" $ do
createDirectoryIfMissing True "tmp/repo"
insideDirectory "tmp/repo" $ do
list ← listCollections
sort list `shouldBe` []
setup ∷ IO ()
setup = createRepo "tmp/repo"
cleanup ∷ ActionWith ()
cleanup () = void (try (removeDirectoryRecursive "tmp/repo") ∷ IO (Either IOException ()))