bloodhound-1.0.0.0: tests/TestsUtils/Generators.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneDeriving #-}
module TestsUtils.Generators where
import Data.Aeson.KeyMap qualified as X
import Data.List qualified as L
import Data.List.NonEmpty qualified as NE
import Data.Map qualified as M
import Data.Scientific (Scientific)
import Data.Text qualified as T
import Data.Versions qualified as Versions
import Database.Bloodhound
import Generic.Random
import TestsUtils.ApproxEq
import TestsUtils.Import
instance Arbitrary NominalDiffTime where
arbitrary = fromInteger <$> arbitrary
#if !MIN_VERSION_QuickCheck(2,8,0)
instance (Arbitrary k, Ord k, Arbitrary v) => Arbitrary (M.Map k v) where
arbitrary = M.fromList <$> arbitrary
#endif
instance Arbitrary Text where
arbitrary = T.pack <$> arbitrary
-- | Used by the ReindexResponse / ReindexSliceStatus round-trip
-- properties to exercise the @requests_per_second@ 'Scientific' field
-- (documented as a potentially fractional "number"). QuickCheck-2.14.3
-- ships no such instance; defined here as an orphan alongside the
-- existing 'Text' / 'UTCTime' / 'NominalDiffTime' orphans in this
-- module. Generates only integer values for round-trip safety —
-- 'Data.Scientific' round-trips arbitrary precision, but integer-valued
-- samples keep the property deterministic across aeson versions.
instance Arbitrary Scientific where
arbitrary = fromInteger <$> arbitrary
instance Arbitrary UTCTime where
arbitrary =
UTCTime
<$> arbitrary
<*> (fromRational . toRational <$> choose (0 :: Double, 86400))
instance Arbitrary Day where
arbitrary =
ModifiedJulianDay . (2000 +) <$> arbitrary
shrink =
(ModifiedJulianDay <$>) . shrink . toModifiedJulianDay
#if MIN_VERSION_QuickCheck(2,10,0) && !MIN_VERSION_QuickCheck(2,17,0)
-- QuickCheck dropped its 'Arbitrary (NonEmpty a)' instance in 2.10 and
-- re-added it in 2.17 (see 'Test.QuickCheck.Arbitrary'). Define our own
-- only for the versions in between; otherwise it would duplicate
-- QuickCheck's.
qcNonEmptyToNonEmpty :: NonEmptyList a -> NonEmpty a
qcNonEmptyToNonEmpty (NonEmpty (a : xs)) = (a :| xs)
qcNonEmptyToNonEmpty (NonEmpty []) = error "NonEmpty was empty!"
instance Arbitrary a => Arbitrary (NonEmpty a) where
arbitrary =
qcNonEmptyToNonEmpty
<$> arbitrary
#endif
arbitraryScore :: Gen Score
arbitraryScore = fmap getPositive <$> arbitrary
instance (Arbitrary a, Typeable a) => Arbitrary (Hit a) where
arbitrary =
Hit
<$> arbitrary
<*> arbitrary
<*> arbitraryScore
<*> arbitrary
<*> return Nothing
<*> arbitrary
<*> arbitrary
<*> return Nothing
instance Arbitrary HitFields where
arbitrary = pure (HitFields M.empty)
shrink = const []
instance Arbitrary HitsTotalRelation where
arbitrary = oneof [pure HTR_EQ, pure HTR_GTE]
instance Arbitrary HitsTotal where
arbitrary = do
tot <- getPositive <$> arbitrary
relation_ <- arbitrary
return $ HitsTotal tot relation_
instance (Arbitrary a, Typeable a) => Arbitrary (SearchHits a) where
arbitrary = reduceSize $ do
tot <- arbitrary
score <- arbitraryScore
hs <- arbitrary
return $ SearchHits tot score hs
reduceSize :: Gen a -> Gen a
reduceSize f = sized $ \n -> resize (n `div` 2) f
arbitraryAlphaNum :: Gen Char
arbitraryAlphaNum =
oneof
[ choose ('a', 'z'),
choose ('A', 'Z'),
choose ('0', '9')
]
instance Arbitrary RoutingValue where
arbitrary = RoutingValue . T.pack <$> listOf1 arbitraryAlphaNum
instance Arbitrary AliasRouting where
arbitrary =
oneof
[ allAlias,
one,
theOther,
both'
]
where
one =
GranularAliasRouting
<$> (Just <$> arbitrary)
<*> pure Nothing
theOther =
GranularAliasRouting Nothing
<$> (Just <$> arbitrary)
both' =
GranularAliasRouting
<$> (Just <$> arbitrary)
<*> (Just <$> arbitrary)
allAlias = AllAliasRouting <$> arbitrary
instance Arbitrary FieldName where
arbitrary =
FieldName
. T.pack
<$> listOf1 arbitraryAlphaNum
instance Arbitrary ScriptFields where
arbitrary =
pure $
ScriptFields $
X.fromList []
shrink = const []
instance Arbitrary ScriptParams where
arbitrary =
pure $
ScriptParams $
X.fromList
[ ("a", Number 42),
("b", String "forty two")
]
shrink = const []
instance Arbitrary RegexpFlags where
arbitrary =
oneof
[ pure AllRegexpFlags,
pure NoRegexpFlags,
SomeRegexpFlags <$> genUniqueFlags
]
where
genUniqueFlags =
NE.fromList . L.nub
<$> listOf1 arbitrary
instance Arbitrary IndexAliasCreate where
arbitrary =
IndexAliasCreate
<$> arbitrary
<*> reduceSize arbitrary
<*> reduceSize arbitrary
<*> reduceSize arbitrary
<*> reduceSize arbitrary
instance Arbitrary Query where
arbitrary =
reduceSize $
oneof
[ TermQuery <$> arbitrary <*> arbitrary,
TermsQuery <$> arbitrary <*> arbitrary,
QueryMatchQuery <$> arbitrary,
QueryMultiMatchQuery <$> arbitrary,
QueryBoolQuery <$> arbitrary,
QueryBoostingQuery <$> arbitrary,
QueryCommonTermsQuery <$> arbitrary,
ConstantScoreQuery <$> arbitrary <*> arbitrary,
QueryDisMaxQuery <$> arbitrary,
QueryFuzzyQuery <$> arbitrary,
QueryHasChildQuery <$> arbitrary,
QueryHasParentQuery <$> arbitrary,
IdsQuery <$> arbitrary,
QueryIndicesQuery <$> arbitrary,
MatchAllQuery <$> arbitrary,
QueryMoreLikeThisQuery <$> arbitrary,
QueryNestedQuery <$> arbitrary,
QueryPrefixQuery <$> arbitrary,
QueryQueryStringQuery <$> arbitrary,
QuerySimpleQueryStringQuery <$> arbitrary,
QueryRangeQuery <$> arbitrary,
QueryRegexpQuery <$> arbitrary
]
-- TODO: Implement shrink
-- shrink = genericShrink
instance Arbitrary Filter where
arbitrary =
Filter <$> arbitrary
shrink (Filter q) =
Filter <$> shrink q
instance Arbitrary ReplicaBounds where
arbitrary =
oneof
[ replicasBounded,
replicasLowerBounded,
pure ReplicasUnbounded
]
where
replicasBounded = do
Positive a <- arbitrary
Positive b <- arbitrary
return (ReplicasBounded a b)
replicasLowerBounded = do
Positive a <- arbitrary
return (ReplicasLowerBounded a)
instance Arbitrary NodeAttrName where
arbitrary =
NodeAttrName
. T.pack
<$> listOf1 arbitraryAlphaNum
instance Arbitrary NodeAttrFilter where
arbitrary = do
n <- arbitrary
xs <- listOf1 (listOf1 arbitraryAlphaNum)
let (s, ss) = unpackConsPartial xs
ts = T.pack <$> s :| ss
return (NodeAttrFilter n ts)
where
-- listOf1 means this shouldn't blow up.
unpackConsPartial (x : xs) = (x, xs)
unpackConsPartial _ = error "unpackConsPartial failed but shouldn't have"
#if MIN_VERSION_versions(6,0,0)
instance Arbitrary VersionNumber where
arbitrary = do
chunks <- Versions.Chunks <$> arbitrary
return $ VersionNumber $ Versions.Version Nothing chunks Nothing Nothing
instance Arbitrary Versions.Chunk where
arbitrary =
oneof
[ Versions.Numeric <$> arbitrary,
do
n <- chooseInt (1, 5)
Versions.Alphanum . T.pack <$> replicateM n (chooseEnum ('a', 'z'))]
#else
instance Arbitrary VersionNumber where
arbitrary = do
chunks <- arbitrary
return $
VersionNumber $
Versions.Version {
Versions._vEpoch = Nothing,
Versions._vChunks = chunks, Versions._vRel = [], Versions._vMeta = Nothing}
instance Arbitrary Versions.VUnit where
arbitrary =
oneof
[ Versions.Digits . fromIntegral <$> chooseInt (0, 1000),
do
n <- chooseInt (1, 5)
Versions.Str . T.pack <$> replicateM n (chooseEnum ('a', 'z'))]
#endif
instance Arbitrary TemplateQueryKeyValuePairs where
arbitrary = TemplateQueryKeyValuePairs . X.fromList <$> arbitrary
shrink (TemplateQueryKeyValuePairs x) = map (TemplateQueryKeyValuePairs . X.fromList) . shrink $ X.toList x
instance Arbitrary IndexName where
arbitrary = do
n <- chooseInt (5, 15)
indewName <- T.pack <$> replicateM n (chooseEnum ('a', 'z'))
return $ either (\e -> error $ "Invalid generated IndexName " <> show indewName <> ":" <> T.unpack e) id $ mkIndexName indewName
instance Arbitrary RolloverConditions where arbitrary = genericArbitraryU
instance Arbitrary RolloverResponse where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary DocId
instance Arbitrary Version where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary BuildHash
deriving newtype instance Arbitrary IndexAliasRouting
deriving newtype instance Arbitrary ShardCount
deriving newtype instance Arbitrary ReplicaCount
deriving newtype instance Arbitrary TemplateName
deriving newtype instance Arbitrary IndexPattern
deriving newtype instance Arbitrary QueryString
deriving newtype instance Arbitrary CacheName
deriving newtype instance Arbitrary CacheKey
deriving newtype instance Arbitrary Existence
deriving newtype instance Arbitrary CutoffFrequency
deriving newtype instance Arbitrary Analyzer
deriving newtype instance Arbitrary MaxExpansions
deriving newtype instance Arbitrary Lenient
deriving newtype instance Arbitrary Tiebreaker
deriving newtype instance Arbitrary Boost
deriving newtype instance Arbitrary BoostTerms
deriving newtype instance Arbitrary MinimumMatch
deriving newtype instance Arbitrary DisableCoord
deriving newtype instance Arbitrary IgnoreTermFrequency
deriving newtype instance Arbitrary MinimumTermFrequency
deriving newtype instance Arbitrary MaxQueryTerms
instance Arbitrary Fuzziness where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary PrefixLength
deriving newtype instance Arbitrary RelationName
deriving newtype instance Arbitrary PercentMatch
deriving newtype instance Arbitrary StopWord
deriving newtype instance Arbitrary QueryPath
deriving newtype instance Arbitrary AllowLeadingWildcard
deriving newtype instance Arbitrary EnablePositionIncrements
deriving newtype instance Arbitrary AnalyzeWildcard
deriving newtype instance Arbitrary MaxWordLength
deriving newtype instance Arbitrary MinWordLength
deriving newtype instance Arbitrary PhraseSlop
deriving newtype instance Arbitrary MinDocFrequency
deriving newtype instance Arbitrary MaxDocFrequency
deriving newtype instance Arbitrary Regexp
deriving newtype instance Arbitrary Rewrite
deriving newtype instance Arbitrary QueryName
deriving newtype instance Arbitrary Format
deriving newtype instance Arbitrary RangeTimeZone
deriving newtype instance Arbitrary CaseInsensitive
deriving newtype instance Arbitrary Transpositions
deriving newtype instance Arbitrary MaxDeterminizedStates
-- | Generates from a fixed set of representative ES date-math expressions
-- rather than the orphan 'Arbitrary Text' (random Unicode). This keeps the
-- values meaningful AND guarantees they are never a valid ISO-8601
-- timestamp, which would otherwise be claimed by the 'UTCTime' arm of
-- 'RangeValue''s decoder and break the 'RangeDateMath' round-trip.
instance Arbitrary DateMathString where
arbitrary =
DateMathString
<$> elements
[ "now",
"now/d",
"now-1d",
"now-7d/d",
"now+1h",
"now-1d/d",
"now||/d",
"2020-01-01||-1d",
"2020-01-01||+1M/d",
"now-1y/y"
]
-- | At least one bound must be 'Just', otherwise the encoder emits @{}@ and
-- the decoder rejects it (matching the @parseRangeValue@ 'nada' fallthrough),
-- which would break the 'RangeQuery' round-trip property.
instance Arbitrary RangeDateMathValue where
arbitrary =
(RangeDateMathValue <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary)
`suchThat` hasBound
where
hasBound v =
isJust (rangeDateMathLt v)
|| isJust (rangeDateMathLte v)
|| isJust (rangeDateMathGt v)
|| isJust (rangeDateMathGte v)
instance Arbitrary RangeRelation where arbitrary = genericArbitraryU
instance Arbitrary SimpleQueryStringQuery where arbitrary = genericArbitraryU
instance Arbitrary FieldOrFields where arbitrary = genericArbitraryU
instance Arbitrary SimpleQueryFlag where arbitrary = genericArbitraryU
instance Arbitrary RegexpQuery where arbitrary = genericArbitraryU
instance Arbitrary QueryStringQuery where arbitrary = genericArbitraryU
instance Arbitrary RangeQuery where arbitrary = genericArbitraryU
instance Arbitrary RangeValue where arbitrary = genericArbitraryU
instance Arbitrary PrefixQuery where arbitrary = genericArbitraryU
instance Arbitrary NestedQuery where arbitrary = genericArbitraryU
instance Arbitrary MoreLikeThisQuery where arbitrary = genericArbitraryU
instance Arbitrary IndicesQuery where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary IgnoreUnmapped
deriving newtype instance Arbitrary MinChildren
deriving newtype instance Arbitrary MaxChildren
deriving newtype instance Arbitrary AggregateParentScore
instance Arbitrary HasParentQuery where arbitrary = genericArbitraryU
instance Arbitrary HasChildQuery where arbitrary = genericArbitraryU
instance Arbitrary FuzzyQuery where arbitrary = genericArbitraryU
instance Arbitrary DisMaxQuery where arbitrary = genericArbitraryU
instance Arbitrary CommonTermsQuery where arbitrary = genericArbitraryU
instance Arbitrary DistanceRange where arbitrary = genericArbitraryU
instance Arbitrary MultiMatchQuery where arbitrary = genericArbitraryU
instance Arbitrary LessThanD where arbitrary = genericArbitraryU
instance Arbitrary LessThanEqD where arbitrary = genericArbitraryU
instance Arbitrary GreaterThanD where arbitrary = genericArbitraryU
instance Arbitrary GreaterThanEqD where arbitrary = genericArbitraryU
instance Arbitrary LessThan where arbitrary = genericArbitraryU
instance Arbitrary LessThanEq where arbitrary = genericArbitraryU
instance Arbitrary GreaterThan where arbitrary = genericArbitraryU
instance Arbitrary GreaterThanEq where arbitrary = genericArbitraryU
instance Arbitrary GeoPoint where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary NullValue
instance Arbitrary MinimumMatchHighLow where arbitrary = genericArbitraryU
instance Arbitrary CommonMinimumMatch where arbitrary = genericArbitraryU
instance Arbitrary BoostingQuery where arbitrary = genericArbitraryU
instance Arbitrary BoolQuery where arbitrary = genericArbitraryU
instance Arbitrary MatchQuery where arbitrary = genericArbitraryU
instance Arbitrary MatchPhraseQuery where arbitrary = genericArbitraryU
instance Arbitrary MatchPhrasePrefixQuery where arbitrary = genericArbitraryU
instance Arbitrary MultiMatchQueryType where arbitrary = genericArbitraryU
instance Arbitrary BooleanOperator where arbitrary = genericArbitraryU
instance Arbitrary ZeroTermsQuery where arbitrary = genericArbitraryU
instance Arbitrary SearchAliasRouting where arbitrary = genericArbitraryU
instance Arbitrary ScoreType where arbitrary = genericArbitraryU
instance Arbitrary Distance where arbitrary = genericArbitraryU
instance Arbitrary DistanceUnit where arbitrary = genericArbitraryU
instance Arbitrary DistanceType where arbitrary = genericArbitraryU
instance Arbitrary OptimizeBbox where arbitrary = genericArbitraryU
instance Arbitrary GeoBoundingBoxConstraint where arbitrary = genericArbitraryU
instance Arbitrary GeoFilterType where arbitrary = genericArbitraryU
instance Arbitrary GeoBoundingBox where arbitrary = genericArbitraryU
instance Arbitrary LatLon where arbitrary = genericArbitraryU
instance Arbitrary RangeExecution where arbitrary = genericArbitraryU
instance Arbitrary RegexpFlag where arbitrary = genericArbitraryU
instance Arbitrary BoolMatch where arbitrary = genericArbitraryU
instance Arbitrary Term where arbitrary = genericArbitraryU
instance Arbitrary IndexMappingsLimits where arbitrary = genericArbitraryU
instance Arbitrary IndexSettings where arbitrary = genericArbitraryU
instance Arbitrary TokenChar where arbitrary = genericArbitraryU
instance Arbitrary Ngram where arbitrary = genericArbitraryU
instance Arbitrary TokenizerDefinition where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary TokenFilter
instance Arbitrary NgramFilter where arbitrary = genericArbitraryU
instance Arbitrary EdgeNgramFilterSide where arbitrary = genericArbitraryU
instance Arbitrary TokenFilterDefinition where arbitrary = genericArbitraryU
instance Arbitrary Language where arbitrary = genericArbitraryU
instance Arbitrary Shingle where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary CharFilter
instance Arbitrary AnalyzerDefinition where arbitrary = genericArbitraryU
-- TODO: This should have a proper generator that doesn't
-- create garbage that has to be filtered out.
instance Arbitrary CharFilterDefinition where
arbitrary =
oneof
[ CharFilterDefinitionMapping
. chomp
<$> arbitrary,
CharFilterDefinitionPatternReplace
<$> arbitrary
<*> arbitrary
<*> arbitrary
]
where
chomp =
M.map T.strip
. M.mapKeys (T.replace "=>" "" . T.strip)
instance Arbitrary Analysis where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary Tokenizer
instance Arbitrary Compression where arbitrary = genericArbitraryU
instance Arbitrary TimeUnits where
arbitrary =
elements
[ TimeUnitDays,
TimeUnitHours,
TimeUnitMinutes,
TimeUnitSeconds,
TimeUnitMilliseconds,
TimeUnitMicroseconds,
TimeUnitNanoseconds
]
instance Arbitrary EsDuration where arbitrary = genericArbitraryU
-- | Hand-written (not generic) so the generated value always round-trips:
-- 'Bytes' must carry a non-negative count (the parser rejects a leading
-- minus sign) and the percent 'Double' must be finite (NaN breaks the
-- Eq-based 'ApproxEq' fallback).
instance Arbitrary DiskWatermark where
arbitrary =
oneof
[ DiskWatermarkPercent <$> choose (0, 1000000 :: Double),
DiskWatermarkBytes . Bytes <$> choose (0, 10 ^ (9 :: Int))
]
deriving newtype instance Arbitrary Bytes
instance Arbitrary AllocationPolicy where arbitrary = genericArbitraryU
instance Arbitrary InitialShardCount where arbitrary = genericArbitraryU
instance Arbitrary FSType where arbitrary = genericArbitraryU
instance Arbitrary CompoundFormat where arbitrary = genericArbitraryU
instance Arbitrary FsSnapshotRepo where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary SnapshotRepoName
instance Arbitrary DirectGeneratorSuggestModeTypes where arbitrary = genericArbitraryU
instance Arbitrary DirectGenerators where arbitrary = genericArbitraryU
instance Arbitrary PhraseSuggesterCollate where arbitrary = genericArbitraryU
instance Arbitrary PhraseSuggesterHighlighter where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary Size
instance Arbitrary PhraseSuggester where arbitrary = genericArbitraryU
-- | 'SuggestTypeContextSuggester' is intentionally absent from this
-- generator: its 'ToJSON' (the @completion@ tag) decodes back as
-- 'SuggestTypeCompletionSuggester' (see 'SuggestType' docs), so
-- including it would violate the @propJSON (Proxy :: Proxy Suggest)@
-- round-trip. 'SuggestTypeCustom' is also absent because there is no
-- 'Arbitrary' instance for its 'Value' payload. Both variants are
-- covered by the pinned wire-shape tests in "Test.SuggestSpec".
instance Arbitrary SuggestType where
arbitrary =
oneof
[ SuggestTypePhraseSuggester <$> arbitrary,
SuggestTypeTermSuggester <$> arbitrary,
SuggestTypeCompletionSuggester <$> arbitrary
]
instance Arbitrary TermSuggesterSort where arbitrary = genericArbitraryU
instance Arbitrary TermSuggesterStringDistance where arbitrary = genericArbitraryU
instance Arbitrary TermSuggester where arbitrary = genericArbitraryU
instance Arbitrary ContextQueryValue where arbitrary = genericArbitraryU
instance Arbitrary CompletionSuggesterFuzzy where arbitrary = genericArbitraryU
instance Arbitrary CompletionSuggester where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary ContextSuggester
instance Arbitrary Suggest where arbitrary = genericArbitraryU
instance Arbitrary FunctionScoreQuery where arbitrary = genericArbitraryU
instance Arbitrary FunctionScoreFunction where arbitrary = genericArbitraryU
instance Arbitrary FunctionScoreFunctions where arbitrary = genericArbitraryU
instance Arbitrary ComponentFunctionScoreFunction where arbitrary = genericArbitraryU
instance Arbitrary Script where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary ScriptLanguage
instance Arbitrary ScriptSource where arbitrary = genericArbitraryU
instance Arbitrary ScoreMode where arbitrary = genericArbitraryU
instance Arbitrary BoostMode where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary Seed
instance Arbitrary FieldValueFactor where arbitrary = genericArbitraryU
deriving newtype instance Arbitrary Weight
deriving newtype instance Arbitrary Factor
deriving newtype instance Arbitrary FactorMissingFieldValue
instance Arbitrary FactorModifier where arbitrary = genericArbitraryU
instance Arbitrary UpdatableIndexSetting where
arbitrary = resize 10 genericArbitraryU
newtype UpdatableIndexSetting'
= UpdatableIndexSetting' UpdatableIndexSetting
deriving stock (Eq, Show, Typeable)
deriving newtype (ToJSON, FromJSON, ApproxEq)
instance Arbitrary UpdatableIndexSetting' where
arbitrary = do
settings <- arbitrary
return $
UpdatableIndexSetting' $ case settings of
RoutingAllocationInclude xs ->
RoutingAllocationInclude (dropDuplicateAttrNames xs)
RoutingAllocationExclude xs ->
RoutingAllocationExclude (dropDuplicateAttrNames xs)
RoutingAllocationRequire xs ->
RoutingAllocationRequire (dropDuplicateAttrNames xs)
x -> x
where
dropDuplicateAttrNames =
NE.fromList . L.nubBy sameAttrName . NE.toList
sameAttrName a b =
nodeAttrFilterName a == nodeAttrFilterName b
shrink (UpdatableIndexSetting' x) = map UpdatableIndexSetting' (shrink x)
instance Arbitrary InnerHits where arbitrary = genericArbitraryU
-- | Drives the ReindexResponse / ReindexRetries round-trip properties
-- in "Test.ReindexResponseSpec". ReindexRetries has no recursion so a
-- plain Applicative generator is enough.
instance Arbitrary ReindexRetries where
arbitrary =
ReindexRetries
<$> arbitrary
<*> arbitrary
-- | Recursive error-cause generator. Depth is hard-capped at 3
-- (independent of QuickCheck's size parameter) and the @root_cause@ /
-- @suppressed@ lists carry at most 2 entries, so generated trees stay
-- small enough for 100 tests + shrinks to run in well under a second.
-- A tighter bound than the obvious @sized (n -> ... n/2 ...)@, which
-- blows up because @listOf1@ sizes its elements at the parent size.
instance Arbitrary ReindexFailureCause where
arbitrary = go maxDepth
where
maxDepth = 3
go 0 =
pure
ReindexFailureCause
{ reindexFailureCauseType = Nothing,
reindexFailureCauseReason = Nothing,
reindexFailureCauseStackTrace = Nothing,
reindexFailureCauseCausedBy = Nothing,
reindexFailureCauseRootCause = Nothing,
reindexFailureCauseSuppressed = Nothing
}
go n =
ReindexFailureCause
<$> arbitrary
<*> arbitrary
<*> arbitrary
<*> oneof [pure Nothing, Just <$> go (n - 1)]
<*> maybeShortList (go (n - 1))
<*> maybeShortList (go (n - 1))
maybeShortList g = do
k <- choose (0, 2)
if k == 0
then pure Nothing
else Just <$> replicateM k g
instance Arbitrary ReindexFailure where
arbitrary =
ReindexFailure
<$> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
-- | Per-slice status. The bare-string 'throttled'/'throttled_until'
-- fields are 'Text' so they reuse the existing 'Arbitrary Text'.
-- 'requests_per_second' is 'Scientific' (now with an 'Arbitrary'
-- instance in this module — see the orphan at the top).
instance Arbitrary ReindexSliceStatus where
arbitrary =
ReindexSliceStatus
<$> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
-- | 'ReindexResponse' covering the full documented response surface
-- (all seventeen top-level fields). 'requests_per_second' is
-- 'Scientific' (now with an 'Arbitrary' instance — see the orphan at
-- the top of this module).
--
-- @failures@ / @slices@ are generated as either 'Nothing' or a
-- @Just@-non-empty list, because the 'omitNulls' encoder drops empty
-- arrays (an empty @failures@ list is semantically identical to an
-- absent @failures@ key). The explicit golden test
-- "decodes an empty failures list as Just []" pins the decode side
-- of that asymmetry.
instance Arbitrary ReindexResponse where
arbitrary =
ReindexResponse
<$> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> maybeNonEmpty arbitrary
<*> maybeNonEmpty arbitrary
<*> arbitrary
<*> arbitrary
where
maybeNonEmpty g =
oneof [pure Nothing, Just <$> listOf1 g]