diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f518144..b2fd4c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ name: CI on: push: tags: - - v[0-9]+.[0-9]+.[0-9]+ + - v[0-9]+.[0-9]+.[0-9]+* branches: - master pull_request: @@ -16,30 +16,54 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Use dotnet CLI + + - name: Use dotnet CLI 6 + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "6.0.x" # SDK Version to use. + + - name: Use dotnet CLI 8 uses: actions/setup-dotnet@v1 with: - dotnet-version: "5.0.x" # SDK Version to use. + dotnet-version: "8.0.x" # SDK Version to use. + + - name: Set env + if: startsWith( github.ref, 'refs/tags/v' ) + run: | + RELEASE_VERSION="${GITHUB_REF#refs/*/}" + echo "RELEASE_VERSION=${RELEASE_VERSION}" >> $GITHUB_ENV + echo "Version=${RELEASE_VERSION:1}" >> $GITHUB_ENV + - name: Build run: | dotnet restore dotnet build -c Release --no-restore - - name: Test - run: dotnet test -c Release --no-restore --no-build --framework net5.0 --logger "GitHubActions;report-warnings=false" + + - name: Test net6.0 + run: dotnet test -c Release --no-restore --no-build --framework net6.0 --logger "GitHubActions;report-warnings=false" + + - name: Test net8.0 + run: dotnet test -c Release --no-restore --no-build --framework net8.0 --logger "GitHubActions;report-warnings=false" + - name: Pack run: dotnet pack -c Release --no-restore --no-build --include-symbols -o out + + - name: Upload Test Results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: verify-test-results + path: | + **/*.received.* - name: Upload artifact - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 with: name: nupkg path: ./out - - name: Set env - if: startsWith( github.ref, 'refs/tags/v' ) - run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Push if: startsWith( github.ref, 'refs/tags/v' ) env: API_KEY: ${{ secrets.NUGET_API_KEY }} SOURCE: "https://api.nuget.org/v3/index.json" run: | - dotnet nuget push ./out/FSharp.Data.JsonSchema.${RELEASE_VERSION:1}.nupkg --skip-duplicate --no-symbols true --source $SOURCE --api-key $API_KEY + dotnet nuget push ./out/*FSharp.Data.JsonSchema.${RELEASE_VERSION:1}.nupkg --skip-duplicate --no-symbols --source $SOURCE --api-key $API_KEY diff --git a/.gitignore b/.gitignore index b04b17e..ee6680e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +# Verify Tests received files +*.received.* + # User-specific files *.suo *.user diff --git a/build.ps1 b/build.ps1 index 0d38c28..e9a7e60 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,4 +1,4 @@ dotnet restore dotnet build -c Release --no-restore -dotnet test -c Release --no-restore --no-build --framework net5.0 +dotnet test -c Release --no-restore --no-build --framework net8.0 dotnet pack -c Release -o bin --no-restore --no-build diff --git a/build.sh b/build.sh index b816886..de6a861 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash + +set -euo pipefail + dotnet restore dotnet build -c Release --no-restore -dotnet test -c Release --no-restore --no-build --framework net5.0 +dotnet test -c Release --no-restore --no-build --framework net8.0 dotnet pack -c Release -o bin --no-restore --no-build diff --git a/src/Directory.Build.props b/src/Directory.Build.props index bd8786a..2eb047f 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,7 @@ - 2.0.2 + 2.1.2 + $(Version) Ryan Riley Ryan Riley https://github.com/panesofglass/FSharp.Data.JsonSchema @@ -16,10 +17,10 @@ true - + true - + true snupkg diff --git a/src/FSharp.Data.JsonSchema/FSharp.Data.JsonSchema.fsproj b/src/FSharp.Data.JsonSchema/FSharp.Data.JsonSchema.fsproj index f427b31..bb0cc8d 100644 --- a/src/FSharp.Data.JsonSchema/FSharp.Data.JsonSchema.fsproj +++ b/src/FSharp.Data.JsonSchema/FSharp.Data.JsonSchema.fsproj @@ -1,14 +1,16 @@  - netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0 + netstandard2.0;netstandard2.1;netcoreapp3.1;net6.0;net8.0 + $(GITHUB_REPOSITORY_OWNER).FSharp.Data.JsonSchema + $(Version) - + - \ No newline at end of file + diff --git a/src/FSharp.Data.JsonSchema/JsonSchema.fs b/src/FSharp.Data.JsonSchema/JsonSchema.fs index e38ab13..6268890 100644 --- a/src/FSharp.Data.JsonSchema/JsonSchema.fs +++ b/src/FSharp.Data.JsonSchema/JsonSchema.fs @@ -5,7 +5,6 @@ open System.Collections.Generic open Microsoft.FSharp.Reflection open Namotion.Reflection open NJsonSchema -open NJsonSchema.Annotations open NJsonSchema.Generation /// Microsoft.FSharp.Reflection helpers @@ -23,31 +22,48 @@ module Reflection = let isOption (y: System.Type) = y.IsGenericType - && typedefof<_ option> = y.GetGenericTypeDefinition() - + && + let def = y.GetGenericTypeDefinition() + def = typedefof<_ option> || def = typedefof> + + let isObjOption (y: System.Type) = + y = typedefof<_ option> || y = typedefof> + let isPrimitive (ty: Type) = ty.IsPrimitive || ty = typeof || ty = typeof -type OptionSchemaProcessor() = - static let optionTy = typedefof> + let isIntegerEnum (ty: Type) = + ty.IsEnum && ty.GetEnumUnderlyingType() = typeof + +module Dictionary = + let getUniqueKey (dict: IDictionary) (key: string) = + let mutable i = 0 + let mutable newKey = key + while dict.ContainsKey(newKey) do + i <- i + 1 + newKey <- sprintf "%s%d" key i + + newKey + +type OptionSchemaProcessor() = member this.Process(context: SchemaProcessorContext) = if - context.Type.IsGenericType - && optionTy.Equals(context.Type.GetGenericTypeDefinition()) + isNull context.Schema.Reference + && Reflection.isOption context.ContextualType.Type then let schema = context.Schema - let cases = FSharpType.GetUnionCases(context.Type) + let cases = FSharpType.GetUnionCases(context.ContextualType.Type) let schemaType = [| for case in cases do match case.Name with - | "None" -> yield JsonObjectType.Null + | "None" | "ValueNone" -> yield JsonObjectType.Null | _ -> let field = case.GetFields() |> Array.head let schema = - context.Generator.Generate(field.PropertyType) + context.Generator.Generate(field.PropertyType, context.Resolver) match schema.Type with | JsonObjectType.None -> @@ -70,12 +86,13 @@ type SingleCaseDuSchemaProcessor() = member this.Process(context: SchemaProcessorContext) = if - FSharpType.IsUnion(context.Type) - && Reflection.allCasesEmpty context.Type + isNull context.Schema.Reference + && FSharpType.IsUnion(context.ContextualType.Type) + && Reflection.allCasesEmpty context.ContextualType.Type then let schema = context.Schema schema.Type <- JsonObjectType.String - let cases = FSharpType.GetUnionCases(context.Type) + let cases = FSharpType.GetUnionCases(context.ContextualType.Type) for case in cases do schema.Enumeration.Add(case.Name) @@ -89,12 +106,13 @@ type MultiCaseDuSchemaProcessor(?casePropertyName) = member this.Process(context: SchemaProcessorContext) = if - FSharpType.IsUnion(context.Type) - && not (Reflection.allCasesEmpty context.Type) - && not (Reflection.isList context.Type) - && not (Reflection.isOption context.Type) + isNull context.Schema.Reference + && FSharpType.IsUnion(context.ContextualType.Type) + && not (Reflection.allCasesEmpty context.ContextualType.Type) + && not (Reflection.isList context.ContextualType.Type) + && not (Reflection.isOption context.ContextualType.Type) then - let cases = FSharpType.GetUnionCases(context.Type) + let cases = FSharpType.GetUnionCases(context.ContextualType.Type) // Set the core schema definition. let schema = context.Schema @@ -102,8 +120,6 @@ type MultiCaseDuSchemaProcessor(?casePropertyName) = schema.IsAbstract <- false schema.AllowAdditionalProperties <- true - let fieldSchemaCache = Dictionary() - // Add schemas for each case. for case in cases do let fields = case.GetFields() @@ -142,45 +158,38 @@ type MultiCaseDuSchemaProcessor(?casePropertyName) = string (Char.ToLowerInvariant field.Name.[0]) + field.Name.Substring(1) - if field.PropertyType.IsGenericType - && field.PropertyType.GetGenericTypeDefinition() = typedefof> then + let generate ( t : Type) = + let isIntegerEnum = Reflection.isIntegerEnum t + if context.Resolver.HasSchema(t, isIntegerEnum) then + context.Resolver.GetSchema(t, isIntegerEnum) + else + let s = context.Generator.Generate(t, context.Resolver) + if (not << Reflection.isPrimitive ) t + && not (context.Resolver.HasSchema(t, isIntegerEnum)) + then + context.Resolver.AddSchema(t, isIntegerEnum, s) + s + + if Reflection.isOption field.PropertyType then let innerTy = field.PropertyType.GetGenericArguments().[0] - let fieldSchema = - match fieldSchemaCache.TryGetValue innerTy with - | true, fs -> fs - | _ -> context.Generator.Generate(innerTy) + let fieldSchema = generate innerTy let prop = if Reflection.isPrimitive innerTy then JsonSchemaProperty(Type = fieldSchema.Type) else - if not (fieldSchemaCache.ContainsKey innerTy) then - context.Resolver.AppendSchema(fieldSchema, typeNameHint = innerTy.Name) - fieldSchemaCache.Add(innerTy, fieldSchema) - JsonSchemaProperty(Reference = fieldSchema) s.Properties.Add(camelCaseFieldName, prop) else - let fieldSchema = - match fieldSchemaCache.TryGetValue field.PropertyType with - | true, fs -> fs - | _ -> context.Generator.Generate(field.PropertyType) + let fieldSchema = generate field.PropertyType let prop = if Reflection.isPrimitive field.PropertyType then JsonSchemaProperty(Type = fieldSchema.Type, Format = fieldSchema.Format) else - if not (fieldSchemaCache.ContainsKey field.PropertyType) then - context.Resolver.AppendSchema( - fieldSchema, - typeNameHint = field.PropertyType.Name - ) - - fieldSchemaCache.Add(field.PropertyType, fieldSchema) - JsonSchemaProperty(Reference = fieldSchema) s.Properties.Add(camelCaseFieldName, prop) @@ -188,13 +197,39 @@ type MultiCaseDuSchemaProcessor(?casePropertyName) = s // Attach each case definition. - schema.Definitions.Add(case.Name, caseSchema) + let name = Dictionary.getUniqueKey schema.Definitions case.Name + // printfn "Adding case %s to dict: %A" name schema.Definitions + schema.Definitions.Add(name, caseSchema) // Add each schema to the anyOf collection. schema.AnyOf.Add(JsonSchema(Reference = caseSchema)) interface ISchemaProcessor with member this.Process(context) = this.Process(context) + +type RecordSchemaProcessor() = + + let isNullableProperty(property: JsonSchemaProperty) = + property.Type.HasFlag JsonObjectType.Null + || property.OneOf |> Seq.exists (fun s -> s.Type.HasFlag JsonObjectType.Null) + + member this.Process(context: SchemaProcessorContext) = + if + isNull context.Schema.Reference + && FSharpType.IsRecord(context.ContextualType.Type) + then + let schema = context.Schema + + for KeyValue(propertyName, property) in schema.Properties do + if (not << isNullableProperty) property then + property.IsRequired <- true + + interface ISchemaProcessor with + member this.Process(context) = this.Process(context) + + + + [] type internal SchemaNameGenerator() = inherit DefaultSchemaNameGenerator() @@ -202,10 +237,9 @@ type internal SchemaNameGenerator() = override this.Generate(ty: Type) = let cachedType = ty.ToCachedType() - if cachedType.Type = typeof> then + if Reflection.isObjOption cachedType.Type then "Any" - elif cachedType.Type.IsGenericType - && cachedType.Type.GetGenericTypeDefinition() = typedefof> then + elif Reflection.isOption cachedType.Type then this.Generate(cachedType.GenericArguments.[0].OriginalType) else base.Generate(ty) @@ -215,10 +249,9 @@ type internal ReflectionService() = inherit DefaultReflectionService() override this.GetDescription(contextualType, defaultReferenceTypeNullHandling, settings) = - if contextualType.Type = typeof> then + if Reflection.isObjOption contextualType.Type then JsonTypeDescription.Create(contextualType, JsonObjectType.Object, true, null) - elif contextualType.Type.IsConstructedGenericType - && contextualType.Type.GetGenericTypeDefinition() = typedefof> then + elif Reflection.isOption contextualType.Type then let typeDescription = this.GetDescription( contextualType.OriginalGenericArguments.[0], @@ -231,6 +264,7 @@ type internal ReflectionService() = else base.GetDescription(contextualType, defaultReferenceTypeNullHandling, settings) + [] type Generator private () = static let cache = @@ -242,12 +276,14 @@ type Generator private () = SerializerOptions = FSharp.Data.Json.DefaultOptions, DefaultReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull, ReflectionService = ReflectionService(), - SchemaNameGenerator = SchemaNameGenerator() + SchemaNameGenerator = SchemaNameGenerator(), + UseXmlDocumentation = true ) settings.SchemaProcessors.Add(OptionSchemaProcessor()) settings.SchemaProcessors.Add(SingleCaseDuSchemaProcessor()) settings.SchemaProcessors.Add(MultiCaseDuSchemaProcessor(?casePropertyName = casePropertyName)) + settings.SchemaProcessors.Add(RecordSchemaProcessor()) fun ty -> JsonSchema.FromType(ty, settings) /// Creates a generator using the specified casePropertyName and generationProviders. diff --git a/src/FSharp.Data.JsonSchema/Serializer.fs b/src/FSharp.Data.JsonSchema/Serializer.fs index dae0cc6..3383178 100644 --- a/src/FSharp.Data.JsonSchema/Serializer.fs +++ b/src/FSharp.Data.JsonSchema/Serializer.fs @@ -3,40 +3,44 @@ namespace FSharp.Data open System.Text.Json open System.Text.Json.Serialization -[] -type Json private () = - static let optionsCache = - System.Collections.Concurrent.ConcurrentDictionary(dict [| Json.DefaultCasePropertyName, Json.DefaultOptions |]) +[] +module private Defaults = + let private jsonFSharpConverterOptions = + JsonFSharpOptions + .Default() + .WithUnionInternalTag() + .WithUnionNamedFields() + .WithUnwrapOption() + .WithSkippableOptionFields() + .WithUnionUnwrapFieldlessTags() + .WithUnionUnwrapSingleCaseUnions(false) - static member internal DefaultCasePropertyName = "kind" + let mkOptions unionTagName = - static member DefaultOptions = - let options = - JsonSerializerOptions(PropertyNamingPolicy = JsonNamingPolicy.CamelCase) + let options = JsonSerializerOptions(PropertyNamingPolicy = JsonNamingPolicy.CamelCase) options.Converters.Add(JsonStringEnumConverter()) options.Converters.Add( JsonFSharpConverter( - JsonUnionEncoding.InternalTag - ||| JsonUnionEncoding.NamedFields - ||| JsonUnionEncoding.UnwrapFieldlessTags - ||| JsonUnionEncoding.UnwrapOption, - unionTagName = Json.DefaultCasePropertyName + jsonFSharpConverterOptions + .WithUnionTagName(unionTagName) ) ) options - (* - JsonSerializerOptions( - Converters=[|Converters.StringEnumConverter() - OptionConverter() - SingleCaseDuConverter() - MultiCaseDuConverter()|], - ContractResolver=Serialization.CamelCasePropertyNamesContractResolver(), - NullValueHandling=NullValueHandling.Ignore) -*) + + +[] +type Json private () = + + static let optionsCache = + System.Collections.Concurrent.ConcurrentDictionary(dict [| Json.DefaultCasePropertyName, Json.DefaultOptions |]) + + static member internal DefaultCasePropertyName = "kind" + + static member DefaultOptions = mkOptions Json.DefaultCasePropertyName static member Serialize(value) = JsonSerializer.Serialize(value, Json.DefaultOptions) @@ -45,22 +49,7 @@ type Json private () = let options = optionsCache.GetOrAdd( casePropertyName, - let options = - JsonSerializerOptions(IgnoreNullValues = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase) - - options.Converters.Add(JsonStringEnumConverter()) - - options.Converters.Add( - JsonFSharpConverter( - JsonUnionEncoding.InternalTag - ||| JsonUnionEncoding.NamedFields - ||| JsonUnionEncoding.UnwrapFieldlessTags - ||| JsonUnionEncoding.UnwrapOption, - unionTagName = casePropertyName - ) - ) - - options + fun key -> mkOptions casePropertyName ) JsonSerializer.Serialize(value, options) @@ -78,26 +67,7 @@ type Json private () = let options = optionsCache.GetOrAdd( casePropertyName, - fun key -> - let options = - JsonSerializerOptions( - IgnoreNullValues = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - ) - - options.Converters.Add(JsonStringEnumConverter()) - - options.Converters.Add( - JsonFSharpConverter( - JsonUnionEncoding.InternalTag - ||| JsonUnionEncoding.NamedFields - ||| JsonUnionEncoding.UnwrapFieldlessTags - ||| JsonUnionEncoding.UnwrapOption, - unionTagName = casePropertyName - ) - ) - - options + fun key -> mkOptions casePropertyName ) JsonSerializer.Deserialize<'T>(json, options = options) @@ -106,26 +76,7 @@ type Json private () = let options = optionsCache.GetOrAdd( casePropertyName, - fun key -> - let options = - JsonSerializerOptions( - IgnoreNullValues = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - ) - - options.Converters.Add(JsonStringEnumConverter()) - - options.Converters.Add( - JsonFSharpConverter( - JsonUnionEncoding.InternalTag - ||| JsonUnionEncoding.NamedFields - ||| JsonUnionEncoding.UnwrapFieldlessTags - ||| JsonUnionEncoding.UnwrapOption, - unionTagName = casePropertyName - ) - ) - - options + fun key -> mkOptions casePropertyName ) JsonSerializer.Deserialize<'T>(json, options = options) @@ -134,26 +85,7 @@ type Json private () = let options = optionsCache.GetOrAdd( casePropertyName, - fun key -> - let options = - JsonSerializerOptions( - IgnoreNullValues = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - ) - - options.Converters.Add(JsonStringEnumConverter()) - - options.Converters.Add( - JsonFSharpConverter( - JsonUnionEncoding.InternalTag - ||| JsonUnionEncoding.NamedFields - ||| JsonUnionEncoding.UnwrapFieldlessTags - ||| JsonUnionEncoding.UnwrapOption, - unionTagName = casePropertyName - ) - ) - - options + fun key -> mkOptions casePropertyName ) JsonSerializer.Deserialize<'T>(&json, options = options) diff --git a/test/FSharp.Data.JsonSchema.Tests/.editorconfig b/test/FSharp.Data.JsonSchema.Tests/.editorconfig new file mode 100644 index 0000000..4171d33 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/.editorconfig @@ -0,0 +1,9 @@ +# Verify settings +[*.{received,verified}.{txt,xml,json}] +charset = "utf-8-bom" +end_of_line = lf +indent_size = unset +indent_style = unset +insert_final_newline = false +tab_width = unset +trim_trailing_whitespace = false \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/.gitattributes b/test/FSharp.Data.JsonSchema.Tests/.gitattributes new file mode 100644 index 0000000..ce824b8 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/.gitattributes @@ -0,0 +1,3 @@ +*.verified.txt text eol=lf working-tree-encoding=UTF-8 +*.verified.xml text eol=lf working-tree-encoding=UTF-8 +*.verified.json text eol=lf working-tree-encoding=UTF-8 diff --git a/test/FSharp.Data.JsonSchema.Tests/Bug10.fs b/test/FSharp.Data.JsonSchema.Tests/Bug10.fs index 9a9cc4e..dd88b91 100644 --- a/test/FSharp.Data.JsonSchema.Tests/Bug10.fs +++ b/test/FSharp.Data.JsonSchema.Tests/Bug10.fs @@ -35,6 +35,7 @@ let tests = "title": "outerReq", "type": "object", "additionalProperties": false, + "required":["outer1"], "properties": { "outer1": { "$ref": "#/definitions/Inner" @@ -44,6 +45,7 @@ let tests = "Inner": { "type": "object", "additionalProperties": false, + "required":["inner1","inner2"], "properties": { "inner1": { "type": "integer", @@ -81,6 +83,7 @@ let tests = "Inner": { "type": "object", "additionalProperties": false, + "required":["inner1","inner2"], "properties": { "inner1": { "type": "integer", diff --git a/test/FSharp.Data.JsonSchema.Tests/FSharp.Data.JsonSchema.Tests.fsproj b/test/FSharp.Data.JsonSchema.Tests/FSharp.Data.JsonSchema.Tests.fsproj index 9bdd0e4..1d9b6ab 100644 --- a/test/FSharp.Data.JsonSchema.Tests/FSharp.Data.JsonSchema.Tests.fsproj +++ b/test/FSharp.Data.JsonSchema.Tests/FSharp.Data.JsonSchema.Tests.fsproj @@ -1,7 +1,8 @@ Exe - netcoreapp3.1;net5.0 + netcoreapp3.1;net6.0;net8.0 + net6.0 false false @@ -20,6 +21,9 @@ + + + - \ No newline at end of file + diff --git a/test/FSharp.Data.JsonSchema.Tests/GeneratorTests.fs b/test/FSharp.Data.JsonSchema.Tests/GeneratorTests.fs index 107f80a..4f01026 100644 --- a/test/FSharp.Data.JsonSchema.Tests/GeneratorTests.fs +++ b/test/FSharp.Data.JsonSchema.Tests/GeneratorTests.fs @@ -2,6 +2,34 @@ module FSharp.Data.JsonSchema.Tests.GeneratorTests open FSharp.Data.JsonSchema open Expecto +open VerifyTests +open VerifyExpecto + +// do VerifyDiffPlex.Initialize() +do ClipboardAccept.Enable() + +let verifySettings = + let s = VerifySettings() + s.UseDirectory("generator-verified") + s + +type VerifyBuilder(name,focusState) = + inherit TestCaseBuilder(name,focusState) + let makeValidFilePath (input: string) : string = + let invalidChars = System.IO.Path.GetInvalidFileNameChars() |> Array.append [| '\''; '"'; '<'; '>'; '|'; '?'; '*'; ':'; '\\'|] + + let replaceChar = '_' + input.Trim() + |> Seq.map(fun c -> if Array.contains c invalidChars then replaceChar else c ) + |> System.String.Concat + + member __.Return<'T>(v:'T) = Verifier.Verify(makeValidFilePath name, v,settings= verifySettings).Wait() + +let verify name = VerifyBuilder(name,Normal) +let fverify name = VerifyBuilder(name,Focused) +let pverify name = VerifyBuilder(name,Pending) + +let json ( schema: NJsonSchema.JsonSchema ) = schema.ToJson() [] let tests = @@ -13,678 +41,98 @@ let tests = testList "schema generation" - [ test "Enum generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "TestEnum", - "type": "string", - "description": "", - "x-enumNames": [ - "First", - "Second", - "Third" - ], - "enum": [ - "First", - "Second", - "Third" - ] -}""" - - let actual = generator (typeof) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + [ verify "Enum generates proper schema" { + return generator typeof |> json + } + + verify "Class generates proper schema" { + return generator typeof |> json + } + + verify "Record generates proper schema" { + return generator typeof |> json + } + + verify "option<'a> generates proper schema" { + return generator typeof> |> json + } + + verify "voption<'a> generates proper schema" { + return generator typeof> |> json } - test "Class generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "TestClass", - "type": "object", - "additionalProperties": false, - "properties": { - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - } - } -}""" - - let actual = generator (typeof) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + verify "option generates proper schema" { + return generator typeof> |> json } - test "Record generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "TestRecord", - "type": "object", - "additionalProperties": false, - "properties": { - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - } - } -}""" - - let actual = generator (typeof) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + verify "voption generates proper schema" { + return generator typeof> |> json } - test "option<'a> generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Any", - "type": [ - "array", - "boolean", - "integer", - "null", - "number", - "object", - "string" - ], - "additionalProperties": false -}""" - - let ty = typeof> - let actual = generator (ty) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + verify "TestSingleDU generates proper schema" { + return generator typeof |> json } - test "option generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Integer", - "type": [ - "integer", - "null" - ], - "format": "int32" -}""" - - let ty = typeof> - let actual = generator (ty) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + verify "Multi-case DU generates proper schema" { + return generator typeof |> json } - test "TestSingleDU generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "TestSingleDU", - "type": "string", - "additionalProperties": false, - "x-enumNames": [ - "Single", - "Double", - "Triple" - ], - "enum": [ - "Single", - "Double", - "Triple" - ] -}""" - - let ty = typeof - let actual = generator (ty) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + verify "Nested generates proper schema" { + return generator typeof |> json } - test "Multi-case DU generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "TestDU", - "definitions": { - "Case": { - "type": "string", - "default": "Case", - "additionalProperties": false, - "x-enumNames": ["Case"], - "enum": ["Case"] - }, - "WithOneField": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "item" - ], - "properties": { - "tag": { - "type": "string", - "default": "WithOneField", - "x-enumNames": ["WithOneField"], - "enum": ["WithOneField"] - }, - "item": { - "type": "integer", - "format": "int32" - } - } - }, - "WithNamedFields": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "name", - "value" - ], - "properties": { - "tag": { - "type": "string", - "default": "WithNamedFields", - "x-enumNames": ["WithNamedFields"], - "enum": ["WithNamedFields"] - }, - "name": { - "type": "string" - }, - "value": { - "type": "number", - "format": "double" - } - } - } - }, - "anyOf": [ - { - "$ref": "#/definitions/Case" - }, - { - "$ref": "#/definitions/WithOneField" - }, - { - "$ref": "#/definitions/WithNamedFields" - } - ] -}""" - - let ty = typeof - let actual = generator (ty) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + verify "RecWithOption generates proper schema" { + return generator typeof |> json } - test "Nested generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Nested", - "definitions": { - "TestRecord": { - "title": "TestRecord", - "type": "object", - "additionalProperties": false, - "properties": { - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - } - } - }, - "Rec": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "item" - ], - "properties": { - "tag": { - "type": "string", - "default": "Rec", - "x-enumNames": [ - "Rec" - ], - "enum": [ - "Rec" - ] - }, - "item": { - "$ref": "#/definitions/TestRecord" - } - } - }, - "TestDU": { - "title": "TestDU", - "definitions": { - "Case": { - "type": "string", - "default": "Case", - "additionalProperties": false, - "x-enumNames": [ - "Case" - ], - "enum": [ - "Case" - ] - }, - "WithOneField": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "item" - ], - "properties": { - "tag": { - "type": "string", - "default": "WithOneField", - "x-enumNames": [ - "WithOneField" - ], - "enum": [ - "WithOneField" - ] - }, - "item": { - "type": "integer", - "format": "int32" - } + verify "RecWithValueOption generates proper schema" { + return generator typeof |> json } - }, - "WithNamedFields": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "name", - "value" - ], - "properties": { - "tag": { - "type": "string", - "default": "WithNamedFields", - "x-enumNames": [ - "WithNamedFields" - ], - "enum": [ - "WithNamedFields" - ] - }, - "name": { - "type": "string" - }, - "value": { - "type": "number", - "format": "double" - } + + verify "RecWithGenericOption generates proper schema" { + return generator typeof> |> json + } + + verify "RecWithArrayOption generates proper schema" { + return generator typeof |> json + } + + verify "RecWithNullable generates proper schema" { + return generator typeof |> json } - } - }, - "anyOf": [ - { - "$ref": "#/definitions/TestDU/definitions/Case" - }, - { - "$ref": "#/definitions/TestDU/definitions/WithOneField" - }, - { - "$ref": "#/definitions/TestDU/definitions/WithNamedFields" - } - ] - }, - "Du": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "item" - ], - "properties": { - "tag": { - "type": "string", - "default": "Du", - "x-enumNames": [ - "Du" - ], - "enum": [ - "Du" - ] - }, - "item": { - "$ref": "#/definitions/TestDU" - } - } - }, - "TestSingleDU": { - "title": "TestSingleDU", - "type": "string", - "additionalProperties": false, - "x-enumNames": [ - "Single", - "Double", - "Triple" - ], - "enum": [ - "Single", - "Double", - "Triple" - ] - }, - "SingleDu": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "item" - ], - "properties": { - "tag": { - "type": "string", - "default": "SingleDu", - "x-enumNames": [ - "SingleDu" - ], - "enum": [ - "SingleDu" - ] - }, - "item": { - "$ref": "#/definitions/TestSingleDU" - } - } - }, - "TestEnum": { - "title": "TestEnum", - "type": "string", - "description": "", - "x-enumNames": [ - "First", - "Second", - "Third" - ], - "enum": [ - "First", - "Second", - "Third" - ] - }, - "Enum": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "item" - ], - "properties": { - "tag": { - "type": "string", - "default": "Enum", - "x-enumNames": [ - "Enum" - ], - "enum": [ - "Enum" - ] - }, - "item": { - "$ref": "#/definitions/TestEnum" - } - } - }, - "TestClass": { - "title": "TestClass", - "type": "object", - "additionalProperties": false, - "properties": { - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - } - } - }, - "Class": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "item" - ], - "properties": { - "tag": { - "type": "string", - "default": "Class", - "x-enumNames": [ - "Class" - ], - "enum": [ - "Class" - ] - }, - "item": { - "$ref": "#/definitions/TestClass" - } - } - }, - "Opt": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag" - ], - "properties": { - "tag": { - "type": "string", - "default": "Opt", - "x-enumNames": [ - "Opt" - ], - "enum": [ - "Opt" - ] - }, - "item": { - "$ref": "#/definitions/TestRecord" - } - } - } - }, - "anyOf": [ - { - "$ref": "#/definitions/Rec" - }, - { - "$ref": "#/definitions/Du" - }, - { - "$ref": "#/definitions/SingleDu" - }, - { - "$ref": "#/definitions/Enum" - }, - { - "$ref": "#/definitions/Class" - }, - { - "$ref": "#/definitions/Opt" - } - ] -}""" - - let actual = generator (typeof) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + + verify "PaginatedResult<'T> generates proper schema" { + return generator typeof> |> json } - test "RecWithOption generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "RecWithOption", - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string" - }, - "description": { - "type": [ - "null", - "string" - ] - } - } -}""" - - let actual = generator (typeof) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + verify "FSharp list generates proper schema" { + return generator typeof |> json } - test "PaginatedResult<'T> generates proper schema" { - let expected = - """{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "PaginatedResultOfObject", - "type": "object", - "additionalProperties": false, - "properties": { - "page": { - "type": "integer", - "format":"int32" - }, - "perPage": { - "type": "integer", - "format": "int32" - }, - "total": { - "type": "integer", - "format": "int32" - }, - "results": { - "type": "array", - "items": {} - } - } -}""" - - let actual = generator (typeof>) - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + verify "FSharp decimal generates correct schema" { + return generator typeof |> json } - - test "FSharp list generates proper schema" { - let expected = """ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "TestList", - "type": "object", - "additionalProperties": false, - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/definitions/TestRecord" - } - } - }, - "definitions": { - "TestRecord": { - "type": "object", - "additionalProperties": false, - "properties": { - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - } - } - } - } -} -""" - let actual = generator typeof - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected + + verify "Record with annotations generates proper schema" { + return generator typeof |> json } - test "FSharp decimal generates correct schema" { - let expected = """ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "TestDecimal", - "type": "object", - "additionalProperties": false, - "properties": { - "test": { - "$ref": "#/definitions/DuWithDecimal" - }, - "total": { - "type": "number", - "format": "decimal" - } - }, - "definitions": { - "DuWithDecimal": { - "definitions": { - "Nothing": { - "type": "string", - "default": "Nothing", - "additionalProperties": false, - "x-enumNames": [ - "Nothing" - ], - "enum": [ - "Nothing" - ] - }, - "Amount": { - "type": "object", - "additionalProperties": false, - "required": [ - "tag", - "item" - ], - "properties": { - "tag": { - "type": "string", - "default": "Amount", - "x-enumNames": [ - "Amount" - ], - "enum": [ - "Amount" - ] - }, - "item": { - "type": "number", - "format": "decimal" - } + + verify "Interdependent DUs generate proper schema" { + return generator typeof |> json } - } - }, - "anyOf": [ - { - "$ref": "#/definitions/DuWithDecimal/definitions/Nothing" - }, - { - "$ref": "#/definitions/DuWithDecimal/definitions/Amount" - } - ] - } - } -} -""" - let actual = generator typeof - "╰〳 ಠ 益 ಠೃ 〵╯" |> equal actual expected - } ] + + verify "DU with array of records generates proper schema" { + return generator typeof |> json + } + + verify "DU with array of DUs generates proper schema" { + return generator typeof |> json + } + + verify "Record with array of records generates proper schema" { + return generator typeof |> json + } + + verify "Interdependent DUs with optional fields generate proper schema" { + return generator typeof |> json + }] diff --git a/test/FSharp.Data.JsonSchema.Tests/JsonSerializationTests.fs b/test/FSharp.Data.JsonSchema.Tests/JsonSerializationTests.fs index 36e79df..edce554 100644 --- a/test/FSharp.Data.JsonSchema.Tests/JsonSerializationTests.fs +++ b/test/FSharp.Data.JsonSchema.Tests/JsonSerializationTests.fs @@ -38,6 +38,36 @@ let tests = Expect.equal actual expected "Expected serializer to convert option to unwrapped value" } + test "ValueOption.None should serialize as null" { + let expected = "null" + let actual = Json.Serialize(ValueNone, "tag") + Expect.equal actual expected "Expected serializer to convert ValueNone null" + } + + test "ValueOption.ValueNone should roundtrip" { + let expected = ValueNone + + let actual = + Json.Deserialize(Json.Serialize(expected, "tag"), "tag") + + Expect.equal actual expected "Expected serializer to convert ValueNone to null" + } + + test "ValueOption.ValueSome(1) should serialize as 1" { + let expected = "1" + let actual = Json.Serialize(ValueSome 1, "tag") + Expect.equal actual expected "Expected serializer to convert option to unwrapped value" + } + + test "ValueOption.ValueSome(1) should roundtrip" { + let expected = ValueSome 1 + + let actual = + Json.Deserialize(Json.Serialize(expected, "tag"), "tag") + + Expect.equal actual expected "Expected serializer to convert option to unwrapped value" + } + test "tuple should serialize as array" { let expected = """["2021-03-01T00:00:00",10.01]""" @@ -265,4 +295,20 @@ let tests = let actual = Json.Deserialize("""{"name":"Ryan"}""") Expect.equal actual expected "Expected serializer to accept missing, optional field" + } + + test "Sequence field required to be explicitly empty" { + Expect.throws + (fun () -> Json.Deserialize>("""{"page":1,"perPage":10,"total":20}""") |> ignore) + "Expected serializer to enforce sequence field" + } + + test "Skippable sequence field not required to be explicitly empty" { + let expected = + { RecWithSkippableSeq.Post = "Hello" + Likes = System.Text.Json.Serialization.Skippable.Skip } + + let actual = Json.Deserialize("""{"post":"Hello"}""") + + Expect.equal actual expected "Expected serializer to accept missing, skippable sequence field" } ] diff --git a/test/FSharp.Data.JsonSchema.Tests/TestTypes.fs b/test/FSharp.Data.JsonSchema.Tests/TestTypes.fs index 2afdd20..760f273 100644 --- a/test/FSharp.Data.JsonSchema.Tests/TestTypes.fs +++ b/test/FSharp.Data.JsonSchema.Tests/TestTypes.fs @@ -6,6 +6,9 @@ type TestClass() = type TestRecord = { FirstName: string; LastName: string } +[] +type TestStructRecord = { A: int; B: float } + type TestList = { Id: int Name: string @@ -47,12 +50,64 @@ type RecWithOption = { Name: string Description: string option } -module Util = - let stripWhitespace text = - System.Text.RegularExpressions.Regex.Replace(text, @"\s+", "") +type RecWithValueOption = + { Count: int voption + Hey: string } + +type RecWithGenericOption<'T> = + { Car: string + CarType: 'T option } + +type RecWithGenericValueOption<'T> = + { Car: string + CarType: 'T voption } + +type RecWithArrayOption = + { Hey: string; Many: string array option } + +type RecWithNullable = + { Need: int + NoNeed: System.Nullable } + +type RecWithSkippableSeq = + { Post: string + Likes: System.Text.Json.Serialization.Skippable } type PaginatedResult<'T> = { Page: int PerPage: int Total: int Results: 'T seq } + +type SingleCaseDU = + | OnlyCase of onlyCase: TestRecord + +open System.ComponentModel.DataAnnotations + +type RecordWithAnnotations = + { [] RegEx: string + [] MaxLength : string + [] Range: int } + +type Chicken = + | Have of Egg + | DontHaveEgg +and Egg = + | Have of Chicken + | DontHaveChicken + +type Even = + | Even of Odd option +and Odd = + | Odd of Even option + + +type RecWithRecArray = { V : TestRecord array } + +type DUWithRecArray = AA | Records of TestRecord array + +type DUWithDUArray = Dus of TestDU array + +module Util = + let stripWhitespace text = + System.Text.RegularExpressions.Regex.Replace(text, @"\s+", "") diff --git a/test/FSharp.Data.JsonSchema.Tests/ValidationTests.fs b/test/FSharp.Data.JsonSchema.Tests/ValidationTests.fs index 6b3e1e2..306d4c8 100644 --- a/test/FSharp.Data.JsonSchema.Tests/ValidationTests.fs +++ b/test/FSharp.Data.JsonSchema.Tests/ValidationTests.fs @@ -30,6 +30,52 @@ let tests = "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) } + test "Record missing field does not validate against schema" { + let schema = generator (typeof) + + let json = """{"firstName":"Ryan"}""" + + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.isError actual + } + + test "Record missing optional field validates against schema" { + let schema = generator (typeof) + + let json = """{"name":"Ryan"}""" + + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.isOk actual + } + + test "Record missing value optional field validates against schema" { + let schema = generator (typeof) + + let json = """{"hey":"Ryan"}""" + + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.isOk actual + } + + test "Record missing nullable field validates against schema" { + let schema = generator (typeof) + + let json = """{"need":1}""" + + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.isOk actual + } + + test "Record missing array field does not validate against schema" { + let schema = generator (typeof) + + let json = """{"id":1,"name":"Ryan"}""" + + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.isError actual + } + + test "None validates against schema for option<_>" { let schema = generator(typeof>) let json = Json.Serialize(None, "tag") @@ -37,6 +83,13 @@ let tests = "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) } + test "ValueNone validates against schema for voption<_>" { + let schema = generator(typeof>) + let json = Json.Serialize(ValueNone, "tag") + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) + } + test "None validates against schema for option" { let schema = generator(typeof>) let json = Json.Serialize(None, "tag") @@ -51,6 +104,13 @@ let tests = "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) } + test "ValueNone validates against schema for voption" { + let schema = generator(typeof>) + let json = Json.Serialize(ValueNone, "tag") + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) + } + test "None validates against schema for option" { let schema = generator(typeof>) let json = Json.Serialize(None, "tag") @@ -58,6 +118,13 @@ let tests = "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) } + test "ValueNone validates against schema for voption" { + let schema = generator(typeof>) + let json = Json.Serialize(ValueNone, "tag") + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) + } + test "Some \"test\" validates against schema for option<_>" { let schema = generator(typeof>) let json = Json.Serialize(Some "test", "tag") @@ -65,8 +132,15 @@ let tests = "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) } + test "ValueSome \"test\" validates against schema for voption<_>" { + let schema = generator(typeof>) + let json = Json.Serialize(ValueSome "test", "tag") + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) + } + test "Some \"test\" validates against schema for option" { - let schema = generator(typeof>) + let schema = generator(typeof>) let json = Json.Serialize(Some "test", "tag") let actual = Validation.validate schema json "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) @@ -86,6 +160,13 @@ let tests = "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) } + test "ValueSome 1 validates against schema for voption" { + let schema = generator(typeof>) + let json = Json.Serialize(ValueSome 1, "tag") + let actual = Validation.validate schema json + "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) + } + test "TestSingleDU.Single validates against schema" { let schema = generator(typeof) let json = Json.Serialize(TestSingleDU.Single, "tag") @@ -127,4 +208,14 @@ let tests = let actual = Validation.validate schema json "╰〳 ಠ 益 ಠೃ 〵╯" |> Expect.equal actual (Ok()) } + + test "SingleCaseDU validates against schema and roundtrips" { + let schema = generator(typeof) + let expected = SingleCaseDU.OnlyCase {FirstName = "Ryan"; LastName = "Riley"} + let json = Json.Serialize(expected, "tag") + do Expect.wantOk (Validation.validate schema json) "Did not validate" + let actual = Json.Deserialize( json, "tag") + Expect.equal actual expected "Did not roundtrip" + } + ] diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Class generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Class generates proper schema.verified.txt new file mode 100644 index 0000000..90a8949 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Class generates proper schema.verified.txt @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TestClass", + "type": "object", + "additionalProperties": false, + "properties": { + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.DU with array of DUs generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.DU with array of DUs generates proper schema.verified.txt new file mode 100644 index 0000000..b8b1206 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.DU with array of DUs generates proper schema.verified.txt @@ -0,0 +1,118 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "DUWithDUArray", + "definitions": { + "TestDU": { + "definitions": { + "Case": { + "type": "string", + "default": "Case", + "additionalProperties": false, + "x-enumNames": [ + "Case" + ], + "enum": [ + "Case" + ] + }, + "WithOneField": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "WithOneField", + "x-enumNames": [ + "WithOneField" + ], + "enum": [ + "WithOneField" + ] + }, + "item": { + "type": "integer", + "format": "int32" + } + } + }, + "WithNamedFields": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "name", + "value" + ], + "properties": { + "tag": { + "type": "string", + "default": "WithNamedFields", + "x-enumNames": [ + "WithNamedFields" + ], + "enum": [ + "WithNamedFields" + ] + }, + "name": { + "type": "string" + }, + "value": { + "type": "number", + "format": "double" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/TestDU/definitions/Case" + }, + { + "$ref": "#/definitions/TestDU/definitions/WithOneField" + }, + { + "$ref": "#/definitions/TestDU/definitions/WithNamedFields" + } + ] + }, + "TestDUOf": { + "type": "array", + "items": { + "$ref": "#/definitions/TestDU" + } + }, + "Dus": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "Dus", + "x-enumNames": [ + "Dus" + ], + "enum": [ + "Dus" + ] + }, + "item": { + "$ref": "#/definitions/TestDUOf" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/Dus" + } + ] +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.DU with array of records generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.DU with array of records generates proper schema.verified.txt new file mode 100644 index 0000000..fac3032 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.DU with array of records generates proper schema.verified.txt @@ -0,0 +1,70 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "DUWithRecArray", + "definitions": { + "AA": { + "type": "string", + "default": "AA", + "additionalProperties": false, + "x-enumNames": [ + "AA" + ], + "enum": [ + "AA" + ] + }, + "TestRecord": { + "type": "object", + "additionalProperties": false, + "required": [ + "firstName", + "lastName" + ], + "properties": { + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + }, + "TestRecordOf": { + "type": "array", + "items": { + "$ref": "#/definitions/TestRecord" + } + }, + "Records": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "Records", + "x-enumNames": [ + "Records" + ], + "enum": [ + "Records" + ] + }, + "item": { + "$ref": "#/definitions/TestRecordOf" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/AA" + }, + { + "$ref": "#/definitions/Records" + } + ] +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Enum generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Enum generates proper schema.verified.txt new file mode 100644 index 0000000..70620cf --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Enum generates proper schema.verified.txt @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TestEnum", + "type": "string", + "description": "", + "x-enumNames": [ + "First", + "Second", + "Third" + ], + "enum": [ + "First", + "Second", + "Third" + ] +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.FSharp decimal generates correct schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.FSharp decimal generates correct schema.verified.txt new file mode 100644 index 0000000..780f5a6 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.FSharp decimal generates correct schema.verified.txt @@ -0,0 +1,68 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TestDecimal", + "type": "object", + "additionalProperties": false, + "required": [ + "test", + "total" + ], + "properties": { + "test": { + "$ref": "#/definitions/DuWithDecimal" + }, + "total": { + "type": "number", + "format": "decimal" + } + }, + "definitions": { + "DuWithDecimal": { + "definitions": { + "Nothing": { + "type": "string", + "default": "Nothing", + "additionalProperties": false, + "x-enumNames": [ + "Nothing" + ], + "enum": [ + "Nothing" + ] + }, + "Amount": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "Amount", + "x-enumNames": [ + "Amount" + ], + "enum": [ + "Amount" + ] + }, + "item": { + "type": "number", + "format": "decimal" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/DuWithDecimal/definitions/Nothing" + }, + { + "$ref": "#/definitions/DuWithDecimal/definitions/Amount" + } + ] + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.FSharp list generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.FSharp list generates proper schema.verified.txt new file mode 100644 index 0000000..2b9dbc7 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.FSharp list generates proper schema.verified.txt @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TestList", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "name", + "records" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/definitions/TestRecord" + } + } + }, + "definitions": { + "TestRecord": { + "type": "object", + "additionalProperties": false, + "required": [ + "firstName", + "lastName" + ], + "properties": { + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Interdependent DUs generate proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Interdependent DUs generate proper schema.verified.txt new file mode 100644 index 0000000..d9cd8eb --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Interdependent DUs generate proper schema.verified.txt @@ -0,0 +1,94 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Chicken", + "definitions": { + "Egg": { + "definitions": { + "Have": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "Have", + "x-enumNames": [ + "Have" + ], + "enum": [ + "Have" + ] + }, + "item": { + "$ref": "#" + } + } + }, + "DontHaveChicken": { + "type": "string", + "default": "DontHaveChicken", + "additionalProperties": false, + "x-enumNames": [ + "DontHaveChicken" + ], + "enum": [ + "DontHaveChicken" + ] + } + }, + "anyOf": [ + { + "$ref": "#/definitions/Egg/definitions/Have" + }, + { + "$ref": "#/definitions/Egg/definitions/DontHaveChicken" + } + ] + }, + "Have": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "Have", + "x-enumNames": [ + "Have" + ], + "enum": [ + "Have" + ] + }, + "item": { + "$ref": "#/definitions/Egg" + } + } + }, + "DontHaveEgg": { + "type": "string", + "default": "DontHaveEgg", + "additionalProperties": false, + "x-enumNames": [ + "DontHaveEgg" + ], + "enum": [ + "DontHaveEgg" + ] + } + }, + "anyOf": [ + { + "$ref": "#/definitions/Have" + }, + { + "$ref": "#/definitions/DontHaveEgg" + } + ] +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Interdependent DUs with optional fields generate proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Interdependent DUs with optional fields generate proper schema.verified.txt new file mode 100644 index 0000000..964ab23 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Interdependent DUs with optional fields generate proper schema.verified.txt @@ -0,0 +1,64 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Even", + "definitions": { + "Odd": { + "definitions": { + "Odd": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag" + ], + "properties": { + "tag": { + "type": "string", + "default": "Odd", + "x-enumNames": [ + "Odd" + ], + "enum": [ + "Odd" + ] + }, + "item": { + "$ref": "#/definitions/Even" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/Odd/definitions/Odd" + } + ] + }, + "Even": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag" + ], + "properties": { + "tag": { + "type": "string", + "default": "Even", + "x-enumNames": [ + "Even" + ], + "enum": [ + "Even" + ] + }, + "item": { + "$ref": "#/definitions/Odd/definitions/Odd" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/Even" + } + ] +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Multi-case DU generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Multi-case DU generates proper schema.verified.txt new file mode 100644 index 0000000..8295a2a --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Multi-case DU generates proper schema.verified.txt @@ -0,0 +1,80 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TestDU", + "definitions": { + "Case": { + "type": "string", + "default": "Case", + "additionalProperties": false, + "x-enumNames": [ + "Case" + ], + "enum": [ + "Case" + ] + }, + "WithOneField": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "WithOneField", + "x-enumNames": [ + "WithOneField" + ], + "enum": [ + "WithOneField" + ] + }, + "item": { + "type": "integer", + "format": "int32" + } + } + }, + "WithNamedFields": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "name", + "value" + ], + "properties": { + "tag": { + "type": "string", + "default": "WithNamedFields", + "x-enumNames": [ + "WithNamedFields" + ], + "enum": [ + "WithNamedFields" + ] + }, + "name": { + "type": "string" + }, + "value": { + "type": "number", + "format": "double" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/Case" + }, + { + "$ref": "#/definitions/WithOneField" + }, + { + "$ref": "#/definitions/WithNamedFields" + } + ] +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Nested generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Nested generates proper schema.verified.txt new file mode 100644 index 0000000..4e139a8 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Nested generates proper schema.verified.txt @@ -0,0 +1,297 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Nested", + "definitions": { + "TestRecord": { + "type": "object", + "additionalProperties": false, + "required": [ + "firstName", + "lastName" + ], + "properties": { + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + }, + "Rec": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "Rec", + "x-enumNames": [ + "Rec" + ], + "enum": [ + "Rec" + ] + }, + "item": { + "$ref": "#/definitions/TestRecord" + } + } + }, + "TestDU": { + "definitions": { + "Case": { + "type": "string", + "default": "Case", + "additionalProperties": false, + "x-enumNames": [ + "Case" + ], + "enum": [ + "Case" + ] + }, + "WithOneField": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "WithOneField", + "x-enumNames": [ + "WithOneField" + ], + "enum": [ + "WithOneField" + ] + }, + "item": { + "type": "integer", + "format": "int32" + } + } + }, + "WithNamedFields": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "name", + "value" + ], + "properties": { + "tag": { + "type": "string", + "default": "WithNamedFields", + "x-enumNames": [ + "WithNamedFields" + ], + "enum": [ + "WithNamedFields" + ] + }, + "name": { + "type": "string" + }, + "value": { + "type": "number", + "format": "double" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/TestDU/definitions/Case" + }, + { + "$ref": "#/definitions/TestDU/definitions/WithOneField" + }, + { + "$ref": "#/definitions/TestDU/definitions/WithNamedFields" + } + ] + }, + "Du": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "Du", + "x-enumNames": [ + "Du" + ], + "enum": [ + "Du" + ] + }, + "item": { + "$ref": "#/definitions/TestDU" + } + } + }, + "TestSingleDU": { + "type": "string", + "additionalProperties": false, + "x-enumNames": [ + "Single", + "Double", + "Triple" + ], + "enum": [ + "Single", + "Double", + "Triple" + ] + }, + "SingleDu": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "SingleDu", + "x-enumNames": [ + "SingleDu" + ], + "enum": [ + "SingleDu" + ] + }, + "item": { + "$ref": "#/definitions/TestSingleDU" + } + } + }, + "TestEnum": { + "type": "string", + "description": "", + "x-enumNames": [ + "First", + "Second", + "Third" + ], + "enum": [ + "First", + "Second", + "Third" + ] + }, + "Enum": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "Enum", + "x-enumNames": [ + "Enum" + ], + "enum": [ + "Enum" + ] + }, + "item": { + "$ref": "#/definitions/TestEnum" + } + } + }, + "TestClass": { + "type": "object", + "additionalProperties": false, + "properties": { + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + }, + "Class": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "Class", + "x-enumNames": [ + "Class" + ], + "enum": [ + "Class" + ] + }, + "item": { + "$ref": "#/definitions/TestClass" + } + } + }, + "Opt": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag" + ], + "properties": { + "tag": { + "type": "string", + "default": "Opt", + "x-enumNames": [ + "Opt" + ], + "enum": [ + "Opt" + ] + }, + "item": { + "$ref": "#/definitions/TestRecord" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/Rec" + }, + { + "$ref": "#/definitions/Du" + }, + { + "$ref": "#/definitions/SingleDu" + }, + { + "$ref": "#/definitions/Enum" + }, + { + "$ref": "#/definitions/Class" + }, + { + "$ref": "#/definitions/Opt" + } + ] +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.PaginatedResult__T_ generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.PaginatedResult__T_ generates proper schema.verified.txt new file mode 100644 index 0000000..ba83769 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.PaginatedResult__T_ generates proper schema.verified.txt @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "PaginatedResultOfObject", + "type": "object", + "additionalProperties": false, + "required": [ + "page", + "perPage", + "total", + "results" + ], + "properties": { + "page": { + "type": "integer", + "format": "int32" + }, + "perPage": { + "type": "integer", + "format": "int32" + }, + "total": { + "type": "integer", + "format": "int32" + }, + "results": { + "type": "array", + "items": {} + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithArrayOption generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithArrayOption generates proper schema.verified.txt new file mode 100644 index 0000000..b3c097e --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithArrayOption generates proper schema.verified.txt @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RecWithArrayOption", + "type": "object", + "additionalProperties": false, + "required": [ + "hey" + ], + "properties": { + "hey": { + "type": "string" + }, + "many": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithGenericOption generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithGenericOption generates proper schema.verified.txt new file mode 100644 index 0000000..083adbe --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithGenericOption generates proper schema.verified.txt @@ -0,0 +1,104 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RecWithGenericOptionOfTestDU", + "type": "object", + "additionalProperties": false, + "required": [ + "car" + ], + "properties": { + "car": { + "type": "string" + }, + "carType": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/definitions/TestDU" + } + ] + } + }, + "definitions": { + "TestDU": { + "definitions": { + "Case": { + "type": "string", + "default": "Case", + "additionalProperties": false, + "x-enumNames": [ + "Case" + ], + "enum": [ + "Case" + ] + }, + "WithOneField": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "item" + ], + "properties": { + "tag": { + "type": "string", + "default": "WithOneField", + "x-enumNames": [ + "WithOneField" + ], + "enum": [ + "WithOneField" + ] + }, + "item": { + "type": "integer", + "format": "int32" + } + } + }, + "WithNamedFields": { + "type": "object", + "additionalProperties": false, + "required": [ + "tag", + "name", + "value" + ], + "properties": { + "tag": { + "type": "string", + "default": "WithNamedFields", + "x-enumNames": [ + "WithNamedFields" + ], + "enum": [ + "WithNamedFields" + ] + }, + "name": { + "type": "string" + }, + "value": { + "type": "number", + "format": "double" + } + } + } + }, + "anyOf": [ + { + "$ref": "#/definitions/TestDU/definitions/Case" + }, + { + "$ref": "#/definitions/TestDU/definitions/WithOneField" + }, + { + "$ref": "#/definitions/TestDU/definitions/WithNamedFields" + } + ] + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithNullable generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithNullable generates proper schema.verified.txt new file mode 100644 index 0000000..e321a86 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithNullable generates proper schema.verified.txt @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RecWithNullable", + "type": "object", + "additionalProperties": false, + "required": [ + "need" + ], + "properties": { + "need": { + "type": "integer", + "format": "int32" + }, + "noNeed": { + "type": [ + "integer", + "null" + ], + "format": "int32" + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithOption generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithOption generates proper schema.verified.txt new file mode 100644 index 0000000..347d076 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithOption generates proper schema.verified.txt @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RecWithOption", + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": [ + "null", + "string" + ] + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithValueOption generates proper schema.DotNet6_0.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithValueOption generates proper schema.DotNet6_0.verified.txt new file mode 100644 index 0000000..45e4ab0 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithValueOption generates proper schema.DotNet6_0.verified.txt @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RecWithValueOption", + "type": "object", + "additionalProperties": false, + "required": [ + "hey" + ], + "properties": { + "count": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "hey": { + "type": "string" + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithValueOption generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithValueOption generates proper schema.verified.txt new file mode 100644 index 0000000..45e4ab0 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.RecWithValueOption generates proper schema.verified.txt @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RecWithValueOption", + "type": "object", + "additionalProperties": false, + "required": [ + "hey" + ], + "properties": { + "count": { + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "hey": { + "type": "string" + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Record generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Record generates proper schema.verified.txt new file mode 100644 index 0000000..1fd0fcb --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Record generates proper schema.verified.txt @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TestRecord", + "type": "object", + "additionalProperties": false, + "required": [ + "firstName", + "lastName" + ], + "properties": { + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Record with annotations generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Record with annotations generates proper schema.verified.txt new file mode 100644 index 0000000..3f2fb83 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Record with annotations generates proper schema.verified.txt @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RecordWithAnnotations", + "type": "object", + "additionalProperties": false, + "required": [ + "regEx", + "maxLength", + "range" + ], + "properties": { + "regEx": { + "type": "string", + "minLength": 1 + }, + "maxLength": { + "type": "string", + "maxLength": 10 + }, + "range": { + "type": "integer", + "format": "int32", + "maximum": 100.0, + "minimum": 0.0 + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Record with array of records generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Record with array of records generates proper schema.verified.txt new file mode 100644 index 0000000..514e653 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.Record with array of records generates proper schema.verified.txt @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "RecWithRecArray", + "type": "object", + "additionalProperties": false, + "required": [ + "v" + ], + "properties": { + "v": { + "type": "array", + "items": { + "$ref": "#/definitions/TestRecord" + } + } + }, + "definitions": { + "TestRecord": { + "type": "object", + "additionalProperties": false, + "required": [ + "firstName", + "lastName" + ], + "properties": { + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.TestSingleDU generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.TestSingleDU generates proper schema.verified.txt new file mode 100644 index 0000000..9ed89e2 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.TestSingleDU generates proper schema.verified.txt @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "TestSingleDU", + "type": "string", + "additionalProperties": false, + "x-enumNames": [ + "Single", + "Double", + "Triple" + ], + "enum": [ + "Single", + "Double", + "Triple" + ] +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.option__a_ generates proper schema.DotNet6_0.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.option__a_ generates proper schema.DotNet6_0.verified.txt new file mode 100644 index 0000000..f8c7798 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.option__a_ generates proper schema.DotNet6_0.verified.txt @@ -0,0 +1,3 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#" +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.option__a_ generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.option__a_ generates proper schema.verified.txt new file mode 100644 index 0000000..f8c7798 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.option__a_ generates proper schema.verified.txt @@ -0,0 +1,3 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#" +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.option_int_ generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.option_int_ generates proper schema.verified.txt new file mode 100644 index 0000000..f542b0c --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.option_int_ generates proper schema.verified.txt @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Integer", + "type": [ + "integer", + "null" + ], + "format": "int32" +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption__a_ generates proper schema.DotNet6_0.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption__a_ generates proper schema.DotNet6_0.verified.txt new file mode 100644 index 0000000..f8c7798 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption__a_ generates proper schema.DotNet6_0.verified.txt @@ -0,0 +1,3 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#" +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption__a_ generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption__a_ generates proper schema.verified.txt new file mode 100644 index 0000000..f8c7798 --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption__a_ generates proper schema.verified.txt @@ -0,0 +1,3 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#" +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption_int_ generates proper schema.DotNet6_0.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption_int_ generates proper schema.DotNet6_0.verified.txt new file mode 100644 index 0000000..f542b0c --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption_int_ generates proper schema.DotNet6_0.verified.txt @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Integer", + "type": [ + "integer", + "null" + ], + "format": "int32" +} \ No newline at end of file diff --git a/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption_int_ generates proper schema.verified.txt b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption_int_ generates proper schema.verified.txt new file mode 100644 index 0000000..f542b0c --- /dev/null +++ b/test/FSharp.Data.JsonSchema.Tests/generator-verified/GeneratorTests.voption_int_ generates proper schema.verified.txt @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Integer", + "type": [ + "integer", + "null" + ], + "format": "int32" +} \ No newline at end of file