bloodhound-1.0.0.0: tests/Test/ExplainOptionsSpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Test.ExplainOptionsSpec (spec) where
import Data.List (sort)
import Data.Text qualified as T
import Database.Bloodhound.Common.Types
import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
-- | Stable ordering for equality. The renderer preserves field-declaration
-- order but tests should compare the set of params, not the order.
normalize :: [(T.Text, Maybe T.Text)] -> [(T.Text, Maybe T.Text)]
normalize = sort
-- | Boolean helpers rendered as @true@/@false@ strings.
boolTrue :: Maybe T.Text
boolTrue = Just "true"
boolFalse :: Maybe T.Text
boolFalse = Just "false"
spec :: Spec
spec =
describe "ExplainOptions URI param rendering" $ do
it "defaultExplainOptions emits no params" $
explainOptionsParams defaultExplainOptions
`shouldBe` []
it "routing renders verbatim" $ do
let opts = defaultExplainOptions {eoRouting = Just "user-42"}
explainOptionsParams opts `shouldBe` [("routing", Just "user-42")]
it "preference renders verbatim" $ do
let opts = defaultExplainOptions {eoPreference = Just "_local"}
explainOptionsParams opts `shouldBe` [("preference", Just "_local")]
it "stored_fields renders verbatim" $ do
let opts = defaultExplainOptions {eoStoredFields = Just "name,age"}
explainOptionsParams opts `shouldBe` [("stored_fields", Just "name,age")]
describe "_source" $ do
it "Just True renders as _source=true" $ do
let opts = defaultExplainOptions {eoSource = Just True}
explainOptionsParams opts `shouldBe` [("_source", boolTrue)]
it "Just False renders as _source=false" $ do
let opts = defaultExplainOptions {eoSource = Just False}
explainOptionsParams opts `shouldBe` [("_source", boolFalse)]
it "_source_includes renders verbatim" $ do
let opts = defaultExplainOptions {eoSourceIncludes = Just "name"}
explainOptionsParams opts `shouldBe` [("_source_includes", Just "name")]
it "_source_excludes renders verbatim" $ do
let opts = defaultExplainOptions {eoSourceExcludes = Just "age"}
explainOptionsParams opts `shouldBe` [("_source_excludes", Just "age")]
describe "lenient" $ do
it "Just True renders as lenient=true" $ do
let opts = defaultExplainOptions {eoLenient = Just True}
explainOptionsParams opts `shouldBe` [("lenient", boolTrue)]
it "Just False renders as lenient=false" $ do
let opts = defaultExplainOptions {eoLenient = Just False}
explainOptionsParams opts `shouldBe` [("lenient", boolFalse)]
-- The ES _explain URI parameter documents AND/OR (uppercase), even
-- though BooleanOperator's JSON encoding is lowercase. Pin the
-- uppercase wire form so a future refactor that reuses ToJSON is
-- caught here.
describe "default_operator" $ do
it "And renders as default_operator=AND (uppercase)" $ do
let opts = defaultExplainOptions {eoDefaultOperator = Just And}
explainOptionsParams opts `shouldBe` [("default_operator", Just "AND")]
it "Or renders as default_operator=OR (uppercase)" $ do
let opts = defaultExplainOptions {eoDefaultOperator = Just Or}
explainOptionsParams opts `shouldBe` [("default_operator", Just "OR")]
it "df renders verbatim" $ do
let opts = defaultExplainOptions {eoDf = Just "message"}
explainOptionsParams opts `shouldBe` [("df", Just "message")]
it "analyzer renders verbatim" $ do
let opts = defaultExplainOptions {eoAnalyzer = Just "standard"}
explainOptionsParams opts `shouldBe` [("analyzer", Just "standard")]
describe "analyze_wildcard" $ do
it "Just True renders as analyze_wildcard=true" $ do
let opts = defaultExplainOptions {eoAnalyzeWildcard = Just True}
explainOptionsParams opts `shouldBe` [("analyze_wildcard", boolTrue)]
it "Just False renders as analyze_wildcard=false" $ do
let opts = defaultExplainOptions {eoAnalyzeWildcard = Just False}
explainOptionsParams opts `shouldBe` [("analyze_wildcard", boolFalse)]
it "renders every field together when all are populated" $ do
let opts =
defaultExplainOptions
{ eoRouting = Just "user-42",
eoPreference = Just "_local",
eoStoredFields = Just "name,age",
eoSource = Just False,
eoSourceIncludes = Just "name",
eoSourceExcludes = Just "age",
eoLenient = Just True,
eoDefaultOperator = Just And,
eoDf = Just "message",
eoAnalyzer = Just "standard",
eoAnalyzeWildcard = Just True
}
let rendered = explainOptionsParams opts
-- Exactly the 11 documented _explain URI parameters.
length rendered `shouldBe` 11
rendered `shouldSatisfy` all (isJust . snd)
normalize rendered
`shouldBe` sort
[ ("routing", Just "user-42"),
("preference", Just "_local"),
("stored_fields", Just "name,age"),
("_source", Just "false"),
("_source_includes", Just "name"),
("_source_excludes", Just "age"),
("lenient", Just "true"),
("default_operator", Just "AND"),
("df", Just "message"),
("analyzer", Just "standard"),
("analyze_wildcard", Just "true")
]
it "explainDocument delegates to explainDocumentWith defaultExplainOptions (no params)" $
-- defaultExplainOptions emits an empty param list, so the base
-- endpoint is wire-identical to the legacy parameterless form.
explainOptionsParams defaultExplainOptions
`shouldBe` []
where
isJust (Just _) = True
isJust Nothing = False