package aceboot::bodyparser

import std.unittest.*
import std.unittest.testmacro.*
import std.collection.*
import aceboot::web.*

@Test
func test_urlencoded_form() {
    let h = HashMap<String, String>()
    h.add("content-type", "application/x-www-form-urlencoded")
    let ctx = Context("POST", "/login", h)
    ctx.setRawBody("user=alice&pass=p%40ss+word&empty=")
    let app = App().use(bodyParser())
    app.handle(ctx)
    @Expect(formValue(ctx, "user").getOrThrow(), "alice")
    @Expect(formValue(ctx, "pass").getOrThrow(), "p@ss word")
    @Expect(formValue(ctx, "empty").getOrThrow(), "")
    @Expect(formValue(ctx, "missing").isNone(), true)
}

@Test
func test_charset_suffix_still_parses() {
    let h = HashMap<String, String>()
    h.add("content-type", "application/x-www-form-urlencoded; charset=utf-8")
    let ctx = Context("POST", "/", h)
    ctx.setRawBody("a=1&b=2")
    App().use(bodyParser()).handle(ctx)
    @Expect(formValue(ctx, "a").getOrThrow(), "1")
    @Expect(formValue(ctx, "b").getOrThrow(), "2")
}

@Test
func test_streaming_request_rejects_body_parser() {
    let h = HashMap<String, String>()
    h.add("content-type", "application/x-www-form-urlencoded")
    let ctx = Context("POST", "/upload", h)
    ctx.setRequestBodyStream(RequestBodyStream({_: Array<UInt8> => 0}))
    App().use(bodyParser()).handle(ctx)
    @Expect(ctx.status, 500u16)
    @Expect(formValue(ctx, "x").isNone(), true)
}

@Test
func test_no_content_type_skips() {
    let ctx = Context.of("GET", "/")
    App().use(bodyParser()).handle(ctx)
    @Expect(formValue(ctx, "x").isNone(), true)
}

@Test
func test_multipart_form() {
    let b = "----TestBoundary"
    let body = "--${b}\r\nContent-Disposition: form-data; name=\"user\"\r\n\r\nalice\r\n--${b}\r\nContent-Disposition: form-data; name=\"role\"\r\n\r\nadmin\r\n--${b}--\r\n"
    let h = HashMap<String, String>()
    h.add("content-type", "multipart/form-data; boundary=${b}")
    let ctx = Context("POST", "/upload", h)
    ctx.setRawBody(body)
    App().use(bodyParser()).handle(ctx)
    @Expect(formValue(ctx, "user").getOrThrow(), "alice")
    @Expect(formValue(ctx, "role").getOrThrow(), "admin")
    @Expect(formValue(ctx, "missing").isNone(), true)
}