-
Notifications
You must be signed in to change notification settings - Fork 59
Expand file tree
/
Copy pathSchema.TypeMappingTests.fs
More file actions
210 lines (155 loc) · 6.8 KB
/
Schema.TypeMappingTests.fs
File metadata and controls
210 lines (155 loc) · 6.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
module SwaggerProvider.Tests.v3_Schema_TypeMappingTests
open System
open Microsoft.OpenApi.Reader
open SwaggerProvider.Internal.v3.Compilers
open Xunit
open FsUnitTyped
/// Compile a minimal OpenAPI v3 schema containing one "TestType" object with a single
/// "Value" property defined by `propYaml`, and return that property's compiled .NET type.
let private compilePropertyType (propYaml: string) (required: bool) : Type =
let requiredBlock =
if required then
" required:\n - Value\n"
else
""
let schemaStr =
sprintf
"""openapi: "3.0.0"
info:
title: TypeMappingTest
version: "1.0.0"
paths: {}
components:
schemas:
TestType:
type: object
%s properties:
Value:
%s"""
requiredBlock
propYaml
let settings = OpenApiReaderSettings()
settings.AddYamlReader()
let readResult =
Microsoft.OpenApi.OpenApiDocument.Parse(schemaStr, settings = settings)
// Ensure the schema was parsed successfully before using it
match readResult.Diagnostic with
| null -> ()
| diagnostic when diagnostic.Errors |> Seq.isEmpty |> not ->
let errorText =
diagnostic.Errors
|> Seq.map string
|> String.concat Environment.NewLine
failwithf "Failed to parse OpenAPI schema:%s%s" Environment.NewLine errorText
| _ -> ()
let schema =
match readResult.Document with
| null -> failwith "Failed to parse OpenAPI schema: Document is null."
| doc -> doc
let defCompiler = DefinitionCompiler(schema, false)
let opCompiler = OperationCompiler(schema, defCompiler, true, false, true)
opCompiler.CompileProvidedClients(defCompiler.Namespace)
let types = defCompiler.Namespace.GetProvidedTypes()
let testType = types |> List.find(fun t -> t.Name = "TestType")
match testType.GetDeclaredProperty("Value") with
| null -> failwith "Property 'Value' not found on TestType"
| prop -> prop.PropertyType
// ── Required primitive types ─────────────────────────────────────────────────
[<Fact>]
let ``required boolean maps to bool``() =
let ty = compilePropertyType " type: boolean\n" true
ty |> shouldEqual typeof<bool>
[<Fact>]
let ``required integer (no format) maps to int32``() =
let ty = compilePropertyType " type: integer\n" true
ty |> shouldEqual typeof<int32>
[<Fact>]
let ``required integer int64 format maps to int64``() =
let ty =
compilePropertyType " type: integer\n format: int64\n" true
ty |> shouldEqual typeof<int64>
[<Fact>]
let ``required number (no format) maps to float32``() =
let ty = compilePropertyType " type: number\n" true
ty |> shouldEqual typeof<float32>
[<Fact>]
let ``required number double format maps to double``() =
let ty =
compilePropertyType " type: number\n format: double\n" true
ty |> shouldEqual typeof<double>
// ── Required string formats ───────────────────────────────────────────────────
[<Fact>]
let ``required string (no format) maps to string``() =
let ty = compilePropertyType " type: string\n" true
ty |> shouldEqual typeof<string>
[<Fact>]
let ``required string date-time format maps to DateTimeOffset``() =
let ty =
compilePropertyType " type: string\n format: date-time\n" true
ty |> shouldEqual typeof<DateTimeOffset>
[<Fact>]
let ``required string date format maps to DateTimeOffset``() =
let ty = compilePropertyType " type: string\n format: date\n" true
ty |> shouldEqual typeof<DateTimeOffset>
[<Fact>]
let ``required string uuid format maps to Guid``() =
let ty = compilePropertyType " type: string\n format: uuid\n" true
ty |> shouldEqual typeof<Guid>
[<Fact>]
let ``required string byte format maps to byte array``() =
let ty = compilePropertyType " type: string\n format: byte\n" true
// DefinitionCompiler creates a rank-1 explicit array via MakeArrayType(1)
ty |> shouldEqual(typeof<byte>.MakeArrayType(1))
[<Fact>]
let ``required string binary format maps to Stream``() =
let ty =
compilePropertyType " type: string\n format: binary\n" true
ty |> shouldEqual typeof<IO.Stream>
// ── Optional (non-required) value types are wrapped in Option<T> ─────────────
[<Fact>]
let ``optional boolean maps to Option<bool>``() =
let ty = compilePropertyType " type: boolean\n" false
ty |> shouldEqual(typedefof<Option<_>>.MakeGenericType(typeof<bool>))
[<Fact>]
let ``optional integer maps to Option<int32>``() =
let ty = compilePropertyType " type: integer\n" false
ty |> shouldEqual(typedefof<Option<_>>.MakeGenericType(typeof<int32>))
[<Fact>]
let ``optional integer int64 maps to Option<int64>``() =
let ty =
compilePropertyType " type: integer\n format: int64\n" false
ty |> shouldEqual(typedefof<Option<_>>.MakeGenericType(typeof<int64>))
[<Fact>]
let ``optional number maps to Option<float32>``() =
let ty = compilePropertyType " type: number\n" false
ty
|> shouldEqual(typedefof<Option<_>>.MakeGenericType(typeof<float32>))
[<Fact>]
let ``optional number double maps to Option<double>``() =
let ty =
compilePropertyType " type: number\n format: double\n" false
ty
|> shouldEqual(typedefof<Option<_>>.MakeGenericType(typeof<double>))
[<Fact>]
let ``optional DateTimeOffset maps to Option<DateTimeOffset>``() =
let ty =
compilePropertyType " type: string\n format: date-time\n" false
ty
|> shouldEqual(typedefof<Option<_>>.MakeGenericType(typeof<DateTimeOffset>))
[<Fact>]
let ``optional Guid maps to Option<Guid>``() =
let ty =
compilePropertyType " type: string\n format: uuid\n" false
ty |> shouldEqual(typedefof<Option<_>>.MakeGenericType(typeof<Guid>))
// ── Optional reference types are NOT wrapped (they are already nullable) ─────
[<Fact>]
let ``optional string is not wrapped in Option``() =
let ty = compilePropertyType " type: string\n" false
// string is a reference type — not wrapped in Option<T> even when non-required
ty |> shouldEqual typeof<string>
[<Fact>]
let ``optional byte array is not wrapped in Option``() =
let ty =
compilePropertyType " type: string\n format: byte\n" false
// byte[*] is a reference type — not wrapped in Option<T>
ty |> shouldEqual(typeof<byte>.MakeArrayType(1))