feature-flipper-0.2.1.2: test/Control/FlipperSpec.hs
module Control.FlipperSpec (main, spec) where
import qualified Data.ByteString.Char8 as C8
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import Test.Hspec
import Control.Flipper
( ActorId(..)
, Features(..)
, Feature(..)
, HasActorId(..)
)
import qualified Control.Flipper as F
import qualified Control.Flipper.Adapters.Memory as FM
main :: IO ()
main = hspec spec
spec :: Spec
spec = do
describe "whenEnabled" $ do
context "the feature is enabled" $
it "evaluates the given monad" $ do
let feature = (F.mkFeature "ADD_ANOTHER_FEATURE") { isEnabled = True }
let featureState = Features $ M.singleton (featureName feature) feature
store <- FM.execFlipperT featureState (F.whenEnabled "ADD_ANOTHER_FEATURE" (F.enable "ANOTHER_FEATURE"))
M.lookup "ANOTHER_FEATURE" (unFeatures store) `shouldBe` Just (F.mkFeature "ANOTHER_FEATURE") { isEnabled = True }
context "the feature is disabled" $
it "does not evaluate the given monad" $ do
let feature = (F.mkFeature "ADD_ANOTHER_FEATURE") { isEnabled = False }
let featureState = Features $ M.singleton (featureName feature) feature
store <- FM.execFlipperT featureState (F.whenEnabled "ADD_ANOTHER_FEATURE" (F.enable "ANOTHER_FEATURE"))
M.lookup "ANOTHER_FEATURE" (unFeatures store) `shouldBe` Nothing
describe "whenEnabledFor" $ do
context "the feature is enabled globally" $
it "evaluates the given monad" $ do
let feature = (F.mkFeature "ADD_ANOTHER_FEATURE") { isEnabled = True }
let featureState = Features $ M.singleton (featureName feature) feature
store <- FM.execFlipperT featureState (F.whenEnabledFor "ADD_ANOTHER_FEATURE" myActor (F.enable "ANOTHER_FEATURE"))
M.lookup "ANOTHER_FEATURE" (unFeatures store) `shouldBe` Just (F.mkFeature "ANOTHER_FEATURE") { isEnabled = True }
context "the feature is enabled for the given actor" $
it "evaluates the given monad" $ do
let feature = (F.mkFeature "ADD_ANOTHER_FEATURE") { enabledActors = S.singleton (actorId myActor), isEnabled = False }
let featureState = Features $ M.singleton (featureName feature) feature
store <- FM.execFlipperT featureState (F.whenEnabledFor "ADD_ANOTHER_FEATURE" myActor (F.enable "ANOTHER_FEATURE"))
M.lookup "ANOTHER_FEATURE" (unFeatures store) `shouldBe` Just (F.mkFeature "ANOTHER_FEATURE") { isEnabled = True }
context "the feature is not enabled for the given actor" $
it "does not evaluate the given monad" $ do
let feature = F.mkFeature "ADD_ANOTHER_FEATURE"
let featureState = Features $ M.singleton (featureName feature) feature
store <- FM.execFlipperT featureState (F.whenEnabledFor "ADD_ANOTHER_FEATURE" myActor (F.enable "ANOTHER_FEATURE"))
M.lookup "ANOTHER_FEATURE" (unFeatures store) `shouldBe` Nothing
describe "enable" $ do
it "enables a new feature key" $
let
featureState = mempty :: Features
result = FM.evalFlipperT featureState (F.enable "NEW_FEATURE" >> F.enabled "NEW_FEATURE")
in
result `shouldReturn` True
it "enables a existing feature key" $
let
feature = (F.mkFeature "FEATURE") { isEnabled = False }
featureState = Features $ M.singleton (featureName feature) feature
result = FM.evalFlipperT featureState (F.enable "FEATURE" >> F.enabled "FEATURE")
in
result `shouldReturn` True
describe "enableFor" $ do
describe "with an existing feature" $ do
it "enables the feature only for the given actor" $ do
let feature = F.mkFeature "FEATURE"
let featureState = Features $ M.singleton (featureName feature) feature
let result1 = FM.evalFlipperT featureState (F.enableFor "FEATURE" myActor >> F.enabledFor "FEATURE" myActor)
let result2 = FM.evalFlipperT featureState (F.enableFor "FEATURE" myActor >> F.enabledFor "FEATURE" myOtherActor)
result1 `shouldReturn` True
result2 `shouldReturn` False
describe "with a non-existant feature" $ do
it "enables the feature only for the given actor" $ do
let featureState = mempty :: Features
let result1 = FM.evalFlipperT featureState (F.enableFor "FEATURE" myActor >> F.enabledFor "FEATURE" myActor)
let result2 = FM.evalFlipperT featureState (F.enableFor "FEATURE" myActor >> F.enabledFor "FEATURE" myOtherActor)
result1 `shouldReturn` True
result2 `shouldReturn` False
describe "enabledFor" $ do
it "returns True if the feature is enabled globally" $ do
let feature = (F.mkFeature "FEATURE") { isEnabled = True }
let featureState = Features $ M.singleton (featureName feature) feature
let result = FM.evalFlipperT featureState (F.enabledFor "FEATURE" myActor)
result `shouldReturn` True
it "returns True if the feature is enabled for the actor" $ do
let feature = (F.mkFeature "FEATURE") { enabledActors = S.singleton (actorId myActor), isEnabled = False }
let featureState = Features $ M.singleton (featureName feature) feature
let result = FM.evalFlipperT featureState (F.enabledFor "FEATURE" myActor)
result `shouldReturn` True
it "returns False if the feature is not enabled for this actor" $ do
let feature = F.mkFeature "FEATURE"
let featureState = Features $ M.singleton (featureName feature) feature
let result = FM.evalFlipperT featureState (F.enabledFor "FEATURE" myActor)
result `shouldReturn` False
describe "disable" $ do
it "disables a new feature key" $
let
featureState = mempty :: Features
result = FM.evalFlipperT featureState (F.disable "NEW_FEATURE" >> F.enabled "NEW_FEATURE")
in
result `shouldReturn` False
it "disables a existing feature key" $
let
feature = (F.mkFeature "FEATURE") { isEnabled = True }
featureState = Features $ M.singleton (featureName feature) feature
result = FM.evalFlipperT featureState (F.disable "FEATURE" >> F.enabled "FEATURE")
in
result `shouldReturn` False
describe "toggle" $ do
it "enables a new feature key" $
let
featureState = mempty :: Features
result = FM.evalFlipperT featureState (F.toggle "NEW_FEATURE" >> F.enabled "NEW_FEATURE")
in
result `shouldReturn` True
it "enables a disabled feature key" $
let
feature = (F.mkFeature "FEATURE") { isEnabled = False }
featureState = Features $ M.singleton (featureName feature) feature
result = FM.evalFlipperT featureState (F.toggle "FEATURE" >> F.enabled "FEATURE")
in
result `shouldReturn` True
it "disables a enabled feature key" $
let
feature = (F.mkFeature "FEATURE") { isEnabled = True }
featureState = Features $ M.singleton (featureName feature) feature
result = FM.evalFlipperT featureState (F.toggle "FEATURE" >> F.enabled "FEATURE")
in
result `shouldReturn` False
describe "enabled" $ do
it "returns True when the feature is enabled" $
let
feature = (F.mkFeature "ENABLED_FEATURE") { isEnabled = True }
featureState = Features $ M.singleton (featureName feature) feature
result = FM.evalFlipperT featureState (F.enabled "ENABLED_FEATURE")
in
result `shouldReturn` True
it "returns False when the feature is not enabled" $
let
feature = (F.mkFeature "DISABLED_FEATURE") { isEnabled = False }
featureState = Features $ M.singleton (featureName feature) feature
result = FM.evalFlipperT featureState (F.enabled "DISABLED_FEATURE")
in
result `shouldReturn` False
it "returns False when the feature key is not found" $
let
featureState = mempty :: Features
result = FM.evalFlipperT featureState (F.enabled "NON_EXISTANT_FEATURE")
in
result `shouldReturn` False
newtype TestActor = TestActor
{ myId :: Int
} deriving (Show, Eq)
instance HasActorId TestActor where
actorId actor = ActorId . C8.pack . show $ myId actor
myActor :: TestActor
myActor = TestActor 1
myOtherActor :: TestActor
myOtherActor = TestActor 2