packages feed

multidir-0.1.0.0: test/Multidir/SelectionSpec.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

module Multidir.SelectionSpec (spec) where

import qualified Data.Map as M
import Multidir.ReadConfig
import Multidir.Selection
import Test.Hspec


{-
shouldBeLeft :: Show b => (a -> IO ()) -> Either a b -> IO ()
shouldBeLeft f = \case
  Left x -> f x
  Right y -> expectationFailure ("was meant to be Left: " <> show y)
-}

shouldBeRight :: Show a => (b -> IO ()) -> Either a b -> IO ()
shouldBeRight f = \case
  Left x -> expectationFailure ("was meant to be Right: " <> show x)
  Right y -> f y

shouldMatch :: String -> FilePath -> Proj -> IO ()
shouldMatch s workingDir proj = let
  t (Selection f) = (workingDir, proj) `shouldSatisfy` uncurry f
  in shouldBeRight t $ parseSelection s

shouldNotMatch :: String -> FilePath -> Proj -> IO ()
shouldNotMatch s workingDir proj = let
  t (Selection f) = (workingDir, proj) `shouldNotSatisfy` uncurry f
  in shouldBeRight t $ parseSelection s

shouldNotParse :: String -> IO ()
shouldNotParse s = case parseSelection s of
  Left _ -> pure ()
  Right _ -> expectationFailure ("Should not parse: " <> s)

spec :: Spec
spec = do

  describe "single tag" $ do
    it "should find a tag (1)" $
      shouldMatch "tagA" "/dir1" (Proj "/dir2" ["tagA", "tagB"] M.empty)
    it "should find a tag (2)" $
      shouldMatch "tagB" "/dir1" (Proj "/dir2" ["tagA", "tagB"] M.empty)
    it "should not find a tag" $
      shouldNotMatch "tagC" "/dir1" (Proj "/dir2" ["tagA", "tagB"] M.empty)

  describe "single dir" $ do
    it "should match directory (subdir)" $
      shouldMatch "{dir11}" "/dir1" (Proj "/dir1/dir11" ["tagA", "tagB"] M.empty)
    it "should match directory (current dir)" $
      shouldMatch "{./}" "/dir1" (Proj "/dir1/dir11" ["tagA", "tagB"] M.empty)
    it "should match directory (absolute dir)" $
      shouldMatch "{/dir1}" "/dir2" (Proj "/dir1/dir11" ["tagA", "tagB"] M.empty)
    it "should not match directory (subdir)" $
      shouldNotMatch "{dir11}" "/dir1" (Proj "/dir1/dir12" ["tagA", "tagB"] M.empty)
    it "should not match directory (absolute dir)" $
      shouldNotMatch "{/dir2}" "/dir2" (Proj "/dir1/dir12" ["tagA", "tagB"] M.empty)

  describe "combinators" $ do
    it "or (1)" $
      shouldMatch "tagA|tagB" "/dir1" (Proj "/dir2" ["tagA", "tagC"] M.empty)
    it "or (2)" $
      shouldMatch "tagB|tagC" "/dir1" (Proj "/dir2" ["tagA", "tagC"] M.empty)
    it "or (3)" $
      shouldNotMatch "tagA|tagB" "/dir1" (Proj "/dir2" ["tagC", "tagD"] M.empty)
    it "and (1)" $
      shouldMatch "tagA&tagB" "/dir1" (Proj "/dir2" ["tagA", "tagB"] M.empty)
    it "and (2)" $
      shouldNotMatch "tagA&tagC" "/dir1" (Proj "/dir2" ["tagA", "tagB"] M.empty)
    it "and (3)" $
      shouldNotMatch "tagA&tagC" "/dir1" (Proj "/dir2" ["tagB", "tagC"] M.empty)
    it "not (1)" $
      shouldMatch "!tagA" "/dir1" (Proj "/dir2" ["tagB"] M.empty)
    it "not (1)" $
      shouldNotMatch "!tagA" "/dir1" (Proj "/dir2" ["tagA"] M.empty)

  describe "miscellaneous parsing failures" $ do
    it "double operators" $ do
      shouldNotParse "&&"
      shouldNotParse "x&&"
      shouldNotParse "&&y"
      shouldNotParse "x&&y"