anchor.diff:    </Piercings>
   </Person>"
   
  -    task {
  -        let! result = app next ctx
  -
  -        match result with
  -        | None -> assertFailf "Result was expected to be %s" expected
  -        | Some ctx ->
  -            Assert.Equal(config.StatusCode, ctx.Response.StatusCode)
  -            if ctx.Response.StatusCode = 200 then
  -                let body = getBody ctx
  -                XmlAssert.equals expected body
  -                Assert.Equal(config.ReturnContentType, ctx.Response |> getContentType)
  -    }
  +let johnDoeAsText = @"First name: John, Last name: Doe, Birth date: 1990-07-12, Height: 1.85, Piercings: [|""ear""; ""nose""|]"
  +    
  +let getNegotiationTestHttpContext
  +    (negotiationConfig : INegotiationConfig)
  +    (jsonSettings : MockJsonSettings option)
  +    (shouldMockXml : bool)
  +    (acceptHeaders : StringValues)
  +    =
  +    let ctx = Substitute.For<HttpContext>()
  +    
  +    let headers = HeaderDictionary()
  +    headers.Add("Accept", acceptHeaders)
  +    
  +    jsonSettings |> Option.iter(fun settings -> mockJson ctx settings)
  +    if shouldMockXml then mockXml ctx
  +    mockNegotiation ctx negotiationConfig
  +    
  +    ctx.Items.Returns (new Dictionary<obj,obj>() :> IDictionary<obj,obj>) |> ignore
  +    ctx.Request.Method.ReturnsForAnyArgs "GET" |> ignore
  +    ctx.Request.Path.ReturnsForAnyArgs (PathString("/auto")) |> ignore
  +    ctx.Request.Headers.ReturnsForAnyArgs(headers) |> ignore
  +    ctx.Response.Body <- new MemoryStream()
  +    ctx.Response.StatusCode <- 200
  +    
  +    ctx
  +    
  +let negotiationTestApp =
  +    GET >=> choose [
  +        route "/"     >=> text "Hello World"
  +        route "/foo"  >=> text "bar"
  +        route "/auto" >=> negotiate johnDoe
  +        setStatusCode 404 >=> text "Not found" ]
  +    
  +let runNegotiationTest (ctx : HttpContext) (expectedString : string) (testChecks : HttpContext -> unit) =
  +    task {
  +        let! result = negotiationTestApp next ctx
  +
  +        match result with
  +        | None -> assertFailf "Result was expected to be %s" expectedString
  +        | Some ctx -> testChecks ctx
  +    }
  +
  +// ---------------------------------
  +// Negotiation tests
  +// ---------------------------------
  +let JsonReturningAcceptHeaderCases =
  +    [
  +        {NegotiationConfig = JsonOnlyNegotiationConfig() :> INegotiationConfig; StatusCode = 200; ReturnContentType = "application/json; charset=utf-8"}
  +        {NegotiationConfig = DefaultNegotiationConfig() :> INegotiationConfig; StatusCode = 200; ReturnContentType = "application/json; charset=utf-8"}
  +    ] |> toTheoryData
  +
  +[<Theory>]
  +[<MemberData("JsonReturningAcceptHeaderCases")>]
  +let ``Get "/auto" with Accept header of "application/json" returns JSON object`` (config : NegotiationConfigWithExpectedResult) =
  +    let ctx = getNegotiationTestHttpContext config.NegotiationConfig (Some (Newtonsoft None)) false (StringValues("application/json")) 
  +    let testChecks (context : HttpContext) =
  +        let body = getBody context
  +        Assert.Equal(johnDoeAsJson, body)
  +        Assert.Equal(config.StatusCode, context.Response.StatusCode)
  +        Assert.Equal(config.ReturnContentType, context.Response |> getContentType)
  +    runNegotiationTest ctx johnDoeAsJson testChecks
  +
  +[<Theory>]
  +[<MemberData("JsonReturningAcceptHeaderCases")>]
  +let ``Get "/auto" with Accept header of "application/xml; q=0.9, application/json" returns JSON object`` (config : NegotiationConfigWithExpectedResult) =
  +    let ctx = getNegotiationTestHttpContext config.NegotiationConfig (Some (Newtonsoft None)) false (StringValues("application/xml; q=0.9, application/json")) 
  +    let testChecks (context : HttpContext) =
  +        Assert.Equal(config.StatusCode, context.Response.StatusCode)
  +        if context.Response.StatusCode = 200 then
  +            let body = getBody context
  +            Assert.Equal(johnDoeAsJson, body)
  +            Assert.Equal(config.ReturnContentType, context.Response |> getContentType)
  +    runNegotiationTest ctx johnDoeAsJson testChecks
  +
  +let XmlReturningAcceptHeaderCases =
  +    [
  +        {NegotiationConfig = JsonOnlyNegotiationConfig() :> INegotiationConfig; StatusCode = 406; ReturnContentType = ""}
  +        {NegotiationConfig = DefaultNegotiationConfig() :> INegotiationConfig; StatusCode = 200; ReturnContentType = "application/xml; charset=utf-8"}
  +    ] |> toTheoryData
  +
  +[<Theory>]
  +[<MemberData("XmlReturningAcceptHeaderCases")>]
  +let ``Get "/auto" with Accept header of "application/xml" returns XML object`` (config : NegotiationConfigWithExpectedResult) =
  +    let ctx = getNegotiationTestHttpContext config.NegotiationConfig None true (StringValues("application/xml"))
  +    let testChecks (context : HttpContext) =
  +        Assert.Equal(config.StatusCode, context.Response.StatusCode)
  +        if context.Response.StatusCode = 200 then
  +            let body = getBody context
  +            XmlAssert.equals johnDoeAsXml body
  +            Assert.Equal(config.ReturnContentType, context.Response |> getContentType)
  +    runNegotiationTest ctx johnDoeAsXml testChecks
   
   let XmlJsonReturningAcceptHeaderCases =
       [
  
positive.code: [<Theory>]
  [<MemberData("HtmlReturningAcceptHeaderCases")>]
  let ``Get "/auto" with Accept header of "text/html" returns a 406 response`` (config : NegotiationConfigWithExpectedResult) =
      let johnDoe =
          {
              FirstName = "John"
              LastName  = "Doe"
              BirthDate = DateTime(1990, 7, 12)
              Height    = 1.85
              Piercings = [| "ear"; "nose" |]
          }
  
      let ctx = Substitute.For<HttpContext>()
      mockNegotiation ctx config.NegotiationConfig
      let app =
          GET >=> choose [
              route "/"     >=> text "Hello World"
              route "/foo"  >=> text "bar"
              route "/auto" >=> negotiate johnDoe
              setStatusCode 404 >=> text "Not found" ]
  
      let headers = HeaderDictionary()
      headers.Add("Accept", StringValues("text/html"))
      ctx.Items.Returns (new Dictionary<obj,obj>() :> IDictionary<obj,obj>) |> ignore
      ctx.Request.Method.ReturnsForAnyArgs "GET" |> ignore
      ctx.Request.Path.ReturnsForAnyArgs (PathString("/auto")) |> ignore
      ctx.Request.Headers.ReturnsForAnyArgs(headers) |> ignore
      ctx.Response.Body <- new MemoryStream()
      ctx.Response.StatusCode <- 200
  
      let expected = "text/html is unacceptable by the server."
  
      task {
          let! result = app next ctx
  
          match result with
          | None -> assertFailf "Result was expected to be %s" expected
          | Some ctx ->
              Assert.Equal(config.StatusCode, ctx.Response.StatusCode)
              if ctx.Response.StatusCode = 406 then
                  let body = getBody ctx
                  Assert.Equal(expected, body)
                  Assert.Equal("text/plain; charset=utf-8", ctx.Response |> getContentType)
      }
  
  [<Theory>]
  [<MemberData("JsonReturningAcceptHeaderCases")>]
  let ``Get "/auto" without an Accept header returns a JSON object`` (config : NegotiationConfigWithExpectedResult) =
      let johnDoe =
          {
              FirstName = "John"
              LastName  = "Doe"
              BirthDate = DateTime(1990, 7, 12)
              Height    = 1.85
              Piercings = [| "ear"; "nose" |]
          }
  
      let ctx = Substitute.For<HttpContext>()
      mockJson ctx (Newtonsoft None)
      mockNegotiation ctx config.NegotiationConfig
      let app =
          GET >=> choose [
              route "/"     >=> text "Hello World"
              route "/foo"  >=> text "bar"
              route "/auto" >=> negotiate johnDoe
              setStatusCode 404 >=> text "Not found" ]
  
      let headers = HeaderDictionary()
      ctx.Items.Returns (new Dictionary<obj,obj>() :> IDictionary<obj,obj>) |> ignore
      ctx.Request.Method.ReturnsForAnyArgs "GET" |> ignore
      ctx.Request.Path.ReturnsForAnyArgs (PathString("/auto")) |> ignore
      ctx.Request.Headers.ReturnsForAnyArgs(headers) |> ignore
      ctx.Response.Body <- new MemoryStream()
      ctx.Response.StatusCode <- 200
  
      let expected = "{\"firstName\":\"John\",\"lastName\":\"Doe\",\"birthDate\":\"1990-07-12T00:00:00\",\"height\":1.85,\"piercings\":[\"ear\",\"nose\"]}"
  
      task {
          let! result = app next ctx
  
          match result with
          | None -> assertFailf "Result was expected to be %s" expected
          | Some ctx ->
              Assert.Equal(config.StatusCode, ctx.Response.StatusCode)
              if ctx.Response.StatusCode = 200 then
                  let body = getBody ctx
                  Assert.Equal(expected, body)
                  Assert.Equal("application/json; charset=utf-8", ctx.Response |> getContentType)
      }
  
  [<Fact>]
  let ``Warbler function should execute inner function each time`` () =
      let ctx = Substitute.For<HttpContext>()
      let inner() = Guid.NewGuid().ToString()
      let app =
          GET >=> choose [
              route "/foo"  >=> text (inner())
              route "/foo2" >=> warbler (fun _ -> text (inner())) ]
          <| next
  
      ctx.Request.Method.ReturnsForAnyArgs "GET" |> ignore
      ctx.Request.Path.ReturnsForAnyArgs (PathString("/foo")) |> ignore
      ctx.Response.Body <- new MemoryStream()
  
      task {
          let! res1 = app ctx
          let result1 = getBody res1.Value
  
          ctx.Response.Body <- new MemoryStream()
  
          let! res2 = app ctx
          let result2 = getBody res2.Value
  
          Assert.Equal(result1, result2)
  
          ctx.Request.Path.ReturnsForAnyArgs (PathString("/foo2")) |> ignore
          ctx.Response.Body <- new MemoryStream()
  
          let! res3 = app ctx
          let result3 = getBody res3.Value
  
          ctx.Response.Body <- new MemoryStream()
  
          let! res4 = app ctx
          let result4 = getBody res4.Value
  
          Assert.False(result3.Equals result4)
      }
  
  [<Fact>]
  let ``GET "/redirect" redirect to "/" `` () =
      let ctx = Substitute.For<HttpContext>()
      let app =
          GET >=> choose [
              route "/"         >=> text "Hello World"
              route "/redirect" >=> redirectTo false "/"
              setStatusCode 404 >=> text "Not found" ]
  
      ctx.Request.Method.ReturnsForAnyArgs "GET" |> ignore
      ctx.Request.Path.ReturnsForAnyArgs (PathString("/redirect")) |> ignore
  
      task {
          let! result = app next ctx
  
          match result with
          | None     -> assertFail "It was expected that the request would be redirected"
          | Some ctx -> ctx.Response.Received().Redirect("/", false)
  
      }
  
  [<Fact>]
  let ``POST "/redirect" redirect to "/" `` () =
      let ctx = Substitute.For<HttpContext>()
      let app =
          POST >=> choose [
              route "/"         >=> text "Hello World"
              route "/redirect" >=> redirectTo true "/"
              setStatusCode 404 >=> text "Not found" ]
  
      ctx.Request.Method.ReturnsForAnyArgs "POST" |> ignore
      ctx.Request.Path.ReturnsForAnyArgs (PathString("/redirect")) |> ignore
  
      task {
          let! result = app next ctx
  
          match result with
          | None     -> assertFail "It was expected that the request would be redirected"
          | Some ctx -> ctx.Response.Received().Redirect("/", true)
      }
negative.code: [<Theory>]
  [<MemberData("XmlJsonReturningAcceptHeaderCases")>]
  let ``Get "/auto" with Accept header of "application/xml, application/json" returns XML object`` (config : NegotiationConfigWithExpectedResult) =
      let ctx = getNegotiationTestHttpContext config.NegotiationConfig (Some (Newtonsoft None)) true (StringValues("application/xml, application/json"))
      let testChecks (context : HttpContext) =
          Assert.Equal(config.StatusCode, context.Response.StatusCode)
          if context.Response.StatusCode = 200 && config.ReturnContentType = "application/xml; charset=utf-8" then
              let body = getBody context
              XmlAssert.equals johnDoeAsXml body
              Assert.Equal(config.ReturnContentType, context.Response |> getContentType)
      runNegotiationTest ctx johnDoeAsXml testChecks
  
  [<Theory>]
  [<MemberData("JsonReturningAcceptHeaderCases")>]
  let ``Get "/auto" with Accept header of "application/json, application/xml" returns JSON object`` (config : NegotiationConfigWithExpectedResult) =
      let ctx = getNegotiationTestHttpContext config.NegotiationConfig (Some (Newtonsoft None)) false (StringValues("application/json, application/xml"))
      let testChecks (context : HttpContext) =
          Assert.Equal(config.StatusCode, context.Response.StatusCode)
          if context.Response.StatusCode = 200 then
              let body = getBody context
              Assert.Equal(johnDoeAsJson, body)
              Assert.Equal(config.ReturnContentType, context.Response |> getContentType)
      runNegotiationTest ctx johnDoeAsJson testChecks
  
  [<Theory>]
  [<MemberData("XmlJsonReturningAcceptHeaderCases")>]
  let ``Get "/auto" with Accept header of "application/json; q=0.5, application/xml" returns XML object`` (config : NegotiationConfigWithExpectedResult) =
      let ctx = getNegotiationTestHttpContext config.NegotiationConfig (Some (Newtonsoft None)) true (StringValues("application/json; q=0.5, application/xml"))
      let testChecks (context : HttpContext) =
          Assert.Equal(config.StatusCode, context.Response.StatusCode)
          if context.Response.StatusCode = 200 && config.ReturnContentType = "application/xml; charset=utf-8" then
              let body = getBody context
              XmlAssert.equals johnDoeAsXml body
              Assert.Equal(config.ReturnContentType, context.Response |> getContentType)
      runNegotiationTest ctx johnDoeAsXml testChecks
  
  [<Theory>]
  [<MemberData("XmlJsonReturningAcceptHeaderCases")>]
  let ``Get "/auto" with Accept header of "application/json; q=0.5, application/xml; q=0.6" returns XML object`` (config : NegotiationConfigWithExpectedResult) =
      let ctx = getNegotiationTestHttpContext config.NegotiationConfig (Some (Newtonsoft None)) true (StringValues("application/json; q=0.5, application/xml; q=0.6"))
      let testChecks (context : HttpContext) =
          Assert.Equal(config.StatusCode, context.Response.StatusCode)
          if context.Response.StatusCode = 200 && config.ReturnContentType = "application/xml; charset=utf-8" then
              let body = getBody context
              XmlAssert.equals johnDoeAsXml body
              Assert.Equal(config.ReturnContentType, context.Response |> getContentType)
      runNegotiationTest ctx johnDoeAsXml testChecks
  
  let TextReturningAcceptHeaderCases =
      [
  