public async Task DoesNotModifyCacheHeaders_WhenNoExceptionIsThrown()
        {
            var expiresTime = DateTime.UtcNow.AddDays(10).ToString("R");
            var expectedResponseBody = "Hello world!";
            var builder = new WebHostBuilder()
                .UseStartup(app =>
                {
                    var transformations = new TransformationCollectionBuilder()
                        .Return(404)
                        .For<Exception>()
                        .Transformations;
                    var options = new ExceptionTransformationOptions(transformations);

                    app.UseExceptionTransformations(options);

                    app.Run(async (httpContext) =>
                    {
                        httpContext.Response.Headers.Add("Cache-Control", new[] { "max-age=3600" });
                        httpContext.Response.Headers.Add("Pragma", new[] { "max-age=3600" });
                        httpContext.Response.Headers.Add("Expires", new[] { expiresTime });
                        httpContext.Response.Headers.Add("ETag", new[] { "abcdef" });

                        await httpContext.Response.WriteAsync(expectedResponseBody);
                    });
                });

            using (var server = new TestServer(builder))
            {
                var client = server.CreateClient();
                var response = await client.GetAsync(string.Empty);
                response.EnsureSuccessStatusCode();
                Assert.Equal(expectedResponseBody, await response.Content.ReadAsStringAsync());
                IEnumerable<string> values;
                Assert.True(response.Headers.TryGetValues("Cache-Control", out values));
                Assert.Single(values);
                Assert.Equal("max-age=3600", values.First());
                Assert.True(response.Headers.TryGetValues("Pragma", out values));
                Assert.Single(values);
                Assert.Equal("max-age=3600", values.First());
                Assert.True(response.Content.Headers.TryGetValues("Expires", out values));
                Assert.Single(values);
                Assert.Equal(expiresTime, values.First());
                Assert.True(response.Headers.TryGetValues("ETag", out values));
                Assert.Single(values);
                Assert.Equal("abcdef", values.First());
            }
        }
        public void Map_WhenInvoked_ReturnsAnInstanceWithTheSameStatusCode()
        {
            // Arrange
            var builder = new TransformationCollectionBuilder();

            // Act
            var newBuilder = builder.Return(404);

            // Assert
            Assert.NotNull(newBuilder);
            Assert.IsAssignableFrom(typeof(MappedTransformationCollectionBuilder), newBuilder);
            Assert.Equal(404, newBuilder.StatusCode);
        }
        public async Task DoesNotClearCacheHeaders_WhenResponseHasAlreadyStarted()
        {
            var expiresTime = DateTime.UtcNow.AddDays(10).ToString("R");
            var builder = new WebHostBuilder()
                .UseStartup(app =>
                {
                    app.Use(async (httpContext, next) =>
                    {
                        Exception exception = null;
                        try
                        {
                            await next();
                        }
                        catch (InvalidOperationException ex)
                        {
                            exception = ex;
                        }

                        Assert.NotNull(exception);
                        Assert.Equal("Something bad happened", exception.Message);
                    });

                    var transformations = new TransformationCollectionBuilder()
                        .Return(404)
                        .For<Exception>()
                        .Transformations;
                    var options = new ExceptionTransformationOptions(transformations);

                    app.UseExceptionTransformations(options);

                    app.Run(async (httpContext) =>
                    {
                        httpContext.Response.Headers.Add("Cache-Control", new[] { "max-age=3600" });
                        httpContext.Response.Headers.Add("Pragma", new[] { "max-age=3600" });
                        httpContext.Response.Headers.Add("Expires", new[] { expiresTime });
                        httpContext.Response.Headers.Add("ETag", new[] { "abcdef" });

                        await httpContext.Response.WriteAsync("Hello");

                        throw new InvalidOperationException("Something bad happened");
                    });
                });

            using (var server = new TestServer(builder))
            {
                var client = server.CreateClient();
                var response = await client.GetAsync(string.Empty);
                response.EnsureSuccessStatusCode();
                Assert.Equal("Hello", await response.Content.ReadAsStringAsync());
                IEnumerable<string> values;
                Assert.True(response.Headers.TryGetValues("Cache-Control", out values));
                Assert.Single(values);
                Assert.Equal("max-age=3600", values.First());
                Assert.True(response.Headers.TryGetValues("Pragma", out values));
                Assert.Single(values);
                Assert.Equal("max-age=3600", values.First());
                Assert.True(response.Content.Headers.TryGetValues("Expires", out values));
                Assert.Single(values);
                Assert.Equal(expiresTime, values.First());
                Assert.True(response.Headers.TryGetValues("ETag", out values));
                Assert.Single(values);
                Assert.Equal("abcdef", values.First());
            }
        }
        public async Task ShouldSetTheStatusCode_OnHandledExceptions()
        {
            var builder = new WebHostBuilder().UseStartup(app =>
            {
                var transformations = new TransformationCollectionBuilder()
                    .Return(404)
                    .For<InvalidOperationException>()
                    .Transformations;
                var options = new ExceptionTransformationOptions(transformations);

                app.UseExceptionTransformations(options);

                app.Run(context =>
                {
                    throw new InvalidOperationException("An error occurred whilst handling the request.");
                });
            });

            using (var server = new TestServer(builder))
            {
                var client = server.CreateClient();
                var response = await client.GetAsync(string.Empty);
                Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
            }
        }
        public async Task ShouldOnlyHandle_UnhandledExceptions()
        {
            var builder = new WebHostBuilder().UseStartup(app =>
            {
                var transformations = new TransformationCollectionBuilder()
                    .Return(404)
                    .For<Exception>()
                    .Transformations;
                var options = new ExceptionTransformationOptions(transformations);

                app.UseExceptionTransformations(options);

                app.Run((RequestDelegate)(async (context) =>
                {
                    context.Response.StatusCode = 500;
                    context.Response.ContentType = "text/plain; charset=utf-8";
                    await context.Response.WriteAsync("An error occurred whilst handling the request.");
                }));
            });

            using (var server = new TestServer(builder))
            {
                var client = server.CreateClient();
                var response = await client.GetAsync(string.Empty);
                Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
                Assert.Equal("An error occurred whilst handling the request.", await response.Content.ReadAsStringAsync());
            }
        }
        public async Task ShoudNotHandleUnhandledExceptions_WhenTheResponseHasAlreadyStarted()
        {
            var builder = new WebHostBuilder().UseStartup(app =>
                {
                    app.Use(async (httpContext, next) =>
                    {
                        Exception exception = null;
                        try
                        {
                            await next();
                        }
                        catch (InvalidOperationException ex)
                        {
                            exception = ex;
                        }

                        Assert.NotNull(exception);
                        Assert.Equal("Something bad happened", exception.Message);
                    });

                    var transformations = new TransformationCollectionBuilder()
                        .Return(404)
                        .For<Exception>()
                        .Transformations;
                    var options = new ExceptionTransformationOptions(transformations);

                    app.UseExceptionTransformations(options);

                    app.Run(async (httpContext) =>
                    {
                        await httpContext.Response.WriteAsync("Hello");
                        throw new InvalidOperationException("Something bad happened");
                    });
                });

            using (var server = new TestServer(builder))
            {
                var client = server.CreateClient();
                var response = await client.GetAsync(string.Empty);
                response.EnsureSuccessStatusCode();
                Assert.Equal("Hello", await response.Content.ReadAsStringAsync());
            }
        }