Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/SwaggerProvider.Runtime/RuntimeHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -312,16 +312,24 @@ module RuntimeHelpers =
| :? IO.Stream as stream -> addFileStream name stream
| :? (IO.Stream[]) as streams -> streams |> Seq.iter(addFileStream name)
| x ->
let strValue = x.ToString() // TODO: serialize? does not work with arrays probably
cnt.Add(toStringContent strValue, name)
let strValue = toParam x

if not(isNull strValue) then
cnt.Add(toStringContent strValue, name)

cnt

let toFormUrlEncodedContent(keyValues: seq<string * obj>) =
let keyValues =
keyValues
|> Seq.filter(snd >> isNull >> not)
|> Seq.map(fun (k, v) -> Collections.Generic.KeyValuePair(k, v.ToString()))
|> Seq.choose(fun (k, v) ->
let param = toParam v

if isNull param then
None
else
Some(Collections.Generic.KeyValuePair(k, param)))

new FormUrlEncodedContent(keyValues)

Expand Down
112 changes: 112 additions & 0 deletions tests/SwaggerProvider.Tests/RuntimeHelpersTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,65 @@ module ToFormUrlEncodedContentTests =
body |> shouldEqual ""
}

[<Fact>]
let ``toFormUrlEncodedContent formats DateTime as ISO 8601``() =
task {
let dt = DateTime(2024, 6, 15, 10, 30, 0, DateTimeKind.Utc)

use content = toFormUrlEncodedContent(seq { ("ts", box dt) })

let! body = content.ReadAsStringAsync()
let encodedValue = body.Substring("ts=".Length)
let decodedValue = WebUtility.UrlDecode(encodedValue)

decodedValue |> shouldEqual(dt.ToString("O"))
}
Comment thread
sergey-tihon marked this conversation as resolved.

[<Fact>]
let ``toFormUrlEncodedContent formats DateTimeOffset as ISO 8601``() =
task {
let dto = DateTimeOffset(2024, 6, 15, 10, 30, 0, TimeSpan.Zero)

use content = toFormUrlEncodedContent(seq { ("ts", box dto) })

let! body = content.ReadAsStringAsync()
let encodedValue = body.Substring("ts=".Length)
let decodedValue = WebUtility.UrlDecode(encodedValue)

decodedValue |> shouldEqual(dto.ToString("O"))
}
Comment thread
sergey-tihon marked this conversation as resolved.

[<Fact>]
let ``toFormUrlEncodedContent formats DateOnly as ISO 8601``() =
task {
let d = DateOnly(2025, 7, 4)
use content = toFormUrlEncodedContent(seq { ("date", box d) })

let! body = content.ReadAsStringAsync()
let encodedValue = body.Substring("date=".Length)
let decodedValue = WebUtility.UrlDecode(encodedValue)

decodedValue |> shouldEqual "2025-07-04"
}

[<Fact>]
let ``toFormUrlEncodedContent skips values when toParam returns null``() =
task {
let nestedNone = box(Some(None: string option))

use content =
toFormUrlEncodedContent(
seq {
("present", box "yes")
("nestedNone", nestedNone)
}
)

let! body = content.ReadAsStringAsync()
body |> shouldContainText "present=yes"
body |> shouldNotContainText "nestedNone"
}


module ToMultipartFormDataContentTests =

Expand Down Expand Up @@ -778,6 +837,59 @@ module ToMultipartFormDataContentTests =

hasFileName |> shouldEqual true

[<Fact>]
let ``toMultipartFormDataContent formats DateTime as ISO 8601``() =
task {
let dt = DateTime(2024, 6, 15, 10, 30, 0, DateTimeKind.Utc)
use content = toMultipartFormDataContent(seq { ("ts", box dt) })
let part = content |> Seq.exactlyOne
let! body = part.ReadAsStringAsync()
body |> shouldEqual(dt.ToString("O"))
}
Comment thread
sergey-tihon marked this conversation as resolved.

[<Fact>]
let ``toMultipartFormDataContent formats DateTimeOffset as ISO 8601``() =
task {
let dto = DateTimeOffset(2024, 6, 15, 10, 30, 0, TimeSpan.Zero)
use content = toMultipartFormDataContent(seq { ("ts", box dto) })
let part = content |> Seq.exactlyOne
let! body = part.ReadAsStringAsync()
body |> shouldEqual(dto.ToString("O"))
}

[<Fact>]
let ``toMultipartFormDataContent formats DateOnly as ISO 8601``() =
task {
let d = DateOnly(2025, 7, 4)
use content = toMultipartFormDataContent(seq { ("date", box d) })
let part = content |> Seq.exactlyOne
let! body = part.ReadAsStringAsync()
body |> shouldEqual "2025-07-04"
}

[<Fact>]
let ``toMultipartFormDataContent skips values when toParam returns null``() =
task {
let nestedNone = box(Some(None: string option))

use content =
toMultipartFormDataContent(
seq {
("present", box "yes")
("nestedNone", nestedNone)
}
)

content |> Seq.length |> shouldEqual 1
let part = content |> Seq.exactlyOne
let! body = part.ReadAsStringAsync()

part.Headers.ContentDisposition.Name.Trim('"')
|> shouldEqual "present"

body |> shouldEqual "yes"
}


/// Test types for getPropertyValues tests.
type PropValWithAttr(value: string) =
Expand Down
Loading