aboutsummaryrefslogtreecommitdiff
path: root/BackEnd/Timeline.Tests/Helpers/ResponseAssertions.cs
blob: 95df3eda8ae7bdeca509348104d13525d0fb76d0 (plain)
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
using FluentAssertions;
using FluentAssertions.Execution;
using FluentAssertions.Formatting;
using FluentAssertions.Primitives;
using System;
using System.Globalization;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Timeline.Models.Converters;
using Timeline.Models.Http;

namespace Timeline.Tests.Helpers
{
    public class HttpResponseMessageValueFormatter : IValueFormatter
    {
        public bool CanHandle(object value)
        {
            return value is HttpResponseMessage;
        }

        public string Format(object value, FormattingContext context, FormatChild formatChild)
        {
            string newline = context.UseLineBreaks ? Environment.NewLine : "";
            string padding = new string('\t', context.Depth);

            var res = (HttpResponseMessage)value;
            return $"{newline}{padding} Status Code: {res.StatusCode}";
        }
    }

    public class HttpResponseMessageAssertions
            : ReferenceTypeAssertions<HttpResponseMessage, HttpResponseMessageAssertions>
    {
        static HttpResponseMessageAssertions()
        {
            Formatter.AddFormatter(new HttpResponseMessageValueFormatter());
        }

        public HttpResponseMessageAssertions(HttpResponseMessage instance)
        {
            Subject = instance;
        }

        protected override string Identifier => "HttpResponseMessage";

        public AndConstraint<HttpResponseMessageAssertions> HaveStatusCode(int expected, string because = "", params object[] becauseArgs)
        {
            return HaveStatusCode((HttpStatusCode)expected, because, becauseArgs);
        }

        public AndConstraint<HttpResponseMessageAssertions> HaveStatusCode(HttpStatusCode expected, string because = "", params object[] becauseArgs)
        {
            Execute.Assertion.BecauseOf(because, becauseArgs)
                .ForCondition(Subject.StatusCode == expected)
                .FailWith("Expected status code of {context:HttpResponseMessage} to be {0}{reason}, but found {1}.", expected, Subject.StatusCode);
            return new AndConstraint<HttpResponseMessageAssertions>(this);
        }

        public async Task<T> HaveAndGetJsonBodyAsync<T>(string because = "", params object[] becauseArgs)
        {
            var a = Execute.Assertion.BecauseOf(because, becauseArgs);

            var body = await Subject.ReadBodyAsJsonAsync<T>();
            if (body == null)
            {
                a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string of type {0}{reason}, but failed to read it or it was not a valid json string.", typeof(T).FullName);
                return default!;
            }
            return body;
        }
    }

    public static class AssertionResponseExtensions
    {
        public static HttpResponseMessageAssertions Should(this HttpResponseMessage instance)
        {
            return new HttpResponseMessageAssertions(instance);
        }

        public static Task<CommonResponse> HaveAndGetCommonBodyAsync(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs)
        {
            return assertions.HaveAndGetJsonBodyAsync<CommonResponse>(because, becauseArgs);
        }

        public static async Task HaveCommonBodyWithCodeAsync(this HttpResponseMessageAssertions assertions, int code, string? message = null, params object[] messageArgs)
        {
            message = string.IsNullOrEmpty(message) ? "" : ", " + string.Format(CultureInfo.CurrentCulture, message, messageArgs);
            var body = await assertions.HaveAndGetCommonBodyAsync("Response body should be CommonResponse{0}", message);
            body.Code.Should().Be(code, "Response body code is not the specified one{0}", message);
        }

        public static Task<CommonDataResponse<TData>> HaveAndGetCommonDataBodyAsync<TData>(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs)
        {
            return assertions.HaveAndGetJsonBodyAsync<CommonDataResponse<TData>>(because, becauseArgs);
        }

        public static async Task BePutAsync(this HttpResponseMessageAssertions assertions, bool create, string because = "", params object[] becauseArgs)
        {
            var body = await assertions.HaveStatusCode(create ? 201 : 200, because, becauseArgs)
                .And.HaveAndGetJsonBodyAsync<CommonPutResponse>(because, becauseArgs);
            body.Code.Should().Be(0);
            body.Data.Create.Should().Be(create);
        }

        public static async Task BeDeleteAsync(this HttpResponseMessageAssertions assertions, bool delete, string because = "", params object[] becauseArgs)
        {
            var body = await assertions.HaveStatusCode(200, because, becauseArgs)
                .And.HaveAndGetJsonBodyAsync<CommonDeleteResponse>(because, becauseArgs);
            body.Code.Should().Be(0);
            body.Data.Delete.Should().Be(delete);
        }

        public static async Task BeInvalidModelAsync(this HttpResponseMessageAssertions assertions, string message = null)
        {
            message = string.IsNullOrEmpty(message) ? "" : ", " + message;
            var body = await assertions.HaveStatusCode(400, "Invalid Model Error must have 400 status code{0}", message)
                .And.HaveAndGetCommonBodyAsync("Invalid Model Error must have CommonResponse body{0}", message);
            body.Code.Should().Be(ErrorCodes.Common.InvalidModel,
                "Invalid Model Error must have code {0} in body{1}",
                ErrorCodes.Common.InvalidModel, message);
        }
    }
}