Skip to content

Commit 3ed50cf

Browse files
committed
Add schemaGenWithFormats to support custom string generators
1 parent 26d8def commit 3ed50cf

File tree

2 files changed

+32
-11
lines changed

2 files changed

+32
-11
lines changed

src/Data/OpenApi/Schema/Generator.hs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import Prelude ()
88
import Prelude.Compat
99

1010
import Control.Lens.Operators
11-
import Control.Monad (filterM)
1211
import Data.Aeson
1312
import Data.Aeson.Types
1413
import qualified Data.HashMap.Strict.InsOrd as M
@@ -19,24 +18,29 @@ import qualified Data.Set as S
1918
import Data.OpenApi
2019
import Data.OpenApi.Declare
2120
import Data.OpenApi.Internal.Schema.Validation (inferSchemaTypes)
21+
import Data.Text (Text)
2222
import qualified Data.Text as T
2323
import qualified Data.Vector as V
24+
import GHC.Stack (HasCallStack)
2425
import Test.QuickCheck (arbitrary)
2526
import Test.QuickCheck.Gen
2627
import Test.QuickCheck.Property
2728

2829
-- | Note: 'schemaGen' may 'error', if schema type is not specified,
2930
-- and cannot be inferred.
30-
schemaGen :: Definitions Schema -> Schema -> Gen Value
31-
schemaGen _ schema
31+
schemaGen :: HasCallStack => Definitions Schema -> Schema -> Gen Value
32+
schemaGen = schemaGenWithFormats (const Nothing)
33+
34+
schemaGenWithFormats :: HasCallStack => (Format -> Maybe (Gen Text)) -> Definitions Schema -> Schema -> Gen Value
35+
schemaGenWithFormats _ _ schema
3236
| Just cases <- schema ^. enum_ = elements cases
33-
schemaGen defns schema
37+
schemaGenWithFormats _ defns schema
3438
| Just variants <- schema ^. oneOf = schemaGen defns =<< elements (dereference defns <$> variants)
35-
schemaGen defns schema =
39+
schemaGenWithFormats formatGen defns schema =
3640
case schema ^. type_ of
3741
Nothing ->
3842
case inferSchemaTypes schema of
39-
[ inferredType ] -> schemaGen defns (schema & type_ ?~ inferredType)
43+
[ inferredType ] -> schemaGenWithFormats formatGen defns (schema & type_ ?~ inferredType)
4044
-- Gen is not MonadFail
4145
_ -> error "unable to infer schema type"
4246
Just OpenApiBoolean -> Bool <$> elements [True, False]
@@ -63,12 +67,16 @@ schemaGen defns schema =
6367
minLength' = fromMaybe 0 $ fromInteger <$> schema ^. minItems
6468
maxLength' = fromMaybe size $ fromInteger <$> schema ^. maxItems
6569
arrayLength <- choose (minLength', max minLength' maxLength')
66-
generatedArray <- vectorOf arrayLength $ schemaGen defns itemSchema
70+
generatedArray <- vectorOf arrayLength $ schemaGenWithFormats formatGen defns itemSchema
6771
return . Array $ V.fromList generatedArray
6872
OpenApiItemsArray refs ->
69-
let itemGens = schemaGen defns . dereference defns <$> refs
73+
let itemGens = schemaGenWithFormats formatGen defns . dereference defns <$> refs
7074
in fmap (Array . V.fromList) $ sequence itemGens
71-
Just OpenApiString -> do
75+
| otherwise -> error "invalid array"
76+
Just OpenApiString
77+
| Just gen <- formatGen =<< schema ^. format ->
78+
String <$> gen
79+
| otherwise -> do
7280
size <- getSize
7381
let minLength' = fromMaybe 0 $ fromInteger <$> schema ^. minLength
7482
let maxLength' = fromMaybe size $ fromInteger <$> schema ^. maxLength
@@ -88,11 +96,11 @@ schemaGen defns schema =
8896
numProps <- choose (minProps', max minProps' maxProps')
8997
let presentKeys = take numProps $ S.toList reqKeys ++ shuffledOptional
9098
let presentProps = M.filterWithKey (\k _ -> k `elem` presentKeys) props
91-
let gens = schemaGen defns <$> presentProps
99+
let gens = schemaGenWithFormats formatGen defns <$> presentProps
92100
additionalGens <- case schema ^. additionalProperties of
93101
Just (AdditionalPropertiesSchema addlSchema) -> do
94102
additionalKeys <- sequence . take (numProps - length presentProps) . repeat $ T.pack <$> arbitrary
95-
return . M.fromList $ zip additionalKeys (repeat . schemaGen defns $ dereference defns addlSchema)
103+
return . M.fromList $ zip additionalKeys (repeat . schemaGenWithFormats formatGen defns $ dereference defns addlSchema)
96104
_ -> return []
97105
x <- sequence $ gens <> additionalGens
98106
return . Object $ M.toHashMap x

test/Data/OpenApi/Schema/GeneratorSpec.hs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ spec = do
9191
prop "MissingProperty" $ shouldNotValidate (Proxy :: Proxy MissingProperty)
9292
prop "WrongPropType" $ shouldNotValidate (Proxy :: Proxy WrongPropType)
9393

94+
describe "schemaGenWithFormats" $ do
95+
it "supports custom string format generators" $ do
96+
let sch = mempty
97+
& type_ ?~ OpenApiString
98+
& format ?~ "custom"
99+
100+
let formatGen fmt = case fmt of
101+
"custom" -> Just (pure "custom")
102+
_ -> Nothing
103+
104+
value <- generate $ schemaGenWithFormats formatGen mempty sch
105+
value `shouldBe` String "custom"
106+
94107
-- =============================
95108
-- Data types and bunk instances
96109
-- =============================

0 commit comments

Comments
 (0)