public async Task PostShouldCreateUser()
        {
            //Arrange
            var expectedUser    = Fakers.User.Generate();
            var usersRepository = A.Fake <IUsersRepository>();

            A.CallTo(() => usersRepository.CreateUserAsync(A <User> .Ignored)).Returns(Task.FromResult(expectedUser));
            A.CallTo(() => usersRepository.FindUserAsync(expectedUser.Id)).Returns(Task.FromResult(expectedUser));
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => usersRepository));
            using var client  = factory.CreateClient();
            var createUserRequest = new CreateUser {
                FirstName = expectedUser.FirstName, LastName = expectedUser.LastName
            };

            //Act
            using var response = await client.PostAsync("/api/v1/users/", JsonSerializer.Serialize(createUserRequest));

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.Created);
            using var getResponse = await client.GetSuccessAsync($"/api/v1/users/{expectedUser.Id}");

            var actualUser = JsonSerializer.Deserialize <JeevesUser>(await getResponse.Content.ReadAsStringAsync());

            actualUser.Should().BeEquivalentTo(expectedUser);
        }
        public async Task PostShouldCreateChallenge()
        {
            //Arrange
            var challenge            = Fakers.Challenge.Generate();
            var challengesRepository = A.Fake <IChallengesRepository>();

            A.CallTo(() => challengesRepository.CreateChallengeAsync(A <Challenge> .Ignored)).Returns(Task.FromResult(challenge));
            A.CallTo(() => challengesRepository.FindChallengeAsync(challenge.Id)).Returns(Task.FromResult(challenge));
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => challengesRepository));
            using var client  = factory.CreateClient();
            var createChallengeRequest = new CreateChallenge()
            {
                Name = challenge.Name
            };

            //Act
            using var response = await client.PostAsync("/api/v1/challenges/", JsonSerializer.Serialize(createChallengeRequest));

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.Created);
            using var getResponse = await client.GetSuccessAsync($"/api/v1/challenges/{challenge.Id}");

            var actualChallenge = JsonSerializer.Deserialize <JeevesChallenge>(await getResponse.Content.ReadAsStringAsync());

            actualChallenge.Should().BeEquivalentTo(challenge);
        }
        public async Task PostShouldCreateAttempt()
        {
            //Arrange
            var attempt            = Fakers.Attempt.Generate();
            var challengeId        = Guid.NewGuid();
            var attemptsRepository = A.Fake <IAttemptsRepository>();

            A.CallTo(() => attemptsRepository.CreateAttemptAsync(A <ChallengeAttempt> .Ignored)).Returns(Task.FromResult(attempt));
            A.CallTo(() => attemptsRepository.FindAttemptAsync(attempt.Id)).Returns(Task.FromResult(attempt));
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => attemptsRepository));
            using var client  = factory.CreateClient();
            var createAttemptRequest = new CreateAttempt()
            {
                Solution = new byte[0]
            };

            //Act
            using var response = await client.PostAsync($"/api/v1/challenges/{challengeId}/attempts", JsonSerializer.Serialize(createAttemptRequest));

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.Created);
            using var getResponse = await client.GetSuccessAsync($"/api/v1/challenges/{challengeId}/attempts/{attempt.Id}");

            var actualAttempt = JsonSerializer.Deserialize <JeevesAttempt>(await getResponse.Content.ReadAsStringAsync());

            actualAttempt.Should().BeEquivalentTo(attempt);
        }
        public async Task GetAllShouldReturnNoContentStatusCodeIfAttemptsDontExist()
        {
            //Arrange
            var attemptsRepository = A.Fake <IAttemptsRepository>();

            A.CallTo(() => attemptsRepository.GetAttemptsAsync()).Returns(new ChallengeAttempt[0]);
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => attemptsRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.GetSuccessAsync($"/api/v1/challenges/{Guid.NewGuid()}/attempts");

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.NoContent);
        }
        public async Task GetAllShouldReturnNoContentStatusCodeIfUsersDontExist()
        {
            //Arrange
            var usersRepository = A.Fake <IUsersRepository>();

            A.CallTo(() => usersRepository.GetUsersAsync()).Returns(new User[0]);
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => usersRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.GetSuccessAsync("/api/v1/users");

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.NoContent);
        }
        public async Task DeleteByIdShouldReturnNotFoundStatusCodeIfUserDoesntExist()
        {
            //Arrange
            var deletedUser     = Fakers.User.Generate();
            var usersRepository = A.Fake <IUsersRepository>();

            A.CallTo(() => usersRepository.FindUserAsync(deletedUser.Id)).Returns(Task.FromResult <User>(null));
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => usersRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.DeleteAsync($"/api/v1/users/{deletedUser.Id}");

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.NotFound);
        }
        public async Task GetByIdShouldReturnNotFoundStatusCodeIfUserDoesntExist()
        {
            //Arrange
            var userId          = Guid.NewGuid();
            var usersRepository = A.Fake <IUsersRepository>();

            A.CallTo(() => usersRepository.FindUserAsync(userId)).Returns <User>(null);
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => usersRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.GetAsync($"/api/v1/users/{userId}");

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.NotFound);
        }
        public async Task GetByIdShouldReturnNotFoundStatusCodeIfAttemptDoesntExist()
        {
            //Arrange
            var attemptId          = Guid.NewGuid();
            var attemptsRepository = A.Fake <IAttemptsRepository>();

            A.CallTo(() => attemptsRepository.FindAttemptAsync(attemptId)).Returns <ChallengeAttempt>(null);
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => attemptsRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.GetAsync($"/api/v1/challenges/{Guid.NewGuid()}/attempts/{attemptId}");

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.NotFound);
        }
        public async Task DeleteByIdShouldReturnNoContentStatusCode()
        {
            //Arrange
            var attempts           = Fakers.Attempt.Generate(10);
            var deletedAttempt     = attempts[3];
            var attemptsRepository = A.Fake <IAttemptsRepository>();

            A.CallTo(() => attemptsRepository.DeleteAttemptAsync(deletedAttempt.Id)).Returns(Task.CompletedTask);
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => attemptsRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.DeleteAsync($"/api/v1/challenges/{Guid.NewGuid()}/attempts/{deletedAttempt.Id}");

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.NoContent);
        }
        public async Task GetAllShouldReturnExactlyTheSameAttempts(int attemptsCount)
        {
            //Arrange
            var expectedAttempts   = Fakers.Attempt.Generate(attemptsCount);
            var attemptsRepository = A.Fake <IAttemptsRepository>();

            A.CallTo(() => attemptsRepository.GetAttemptsAsync()).Returns(expectedAttempts);
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => attemptsRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.GetSuccessAsync($"/api/v1/challenges/{Guid.NewGuid()}/attempts");

            var attempts = JsonSerializer.Deserialize <JeevesAttempt[]>(await response.Content.ReadAsStringAsync());

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.OK);
            attempts.Should().BeEquivalentTo(expectedAttempts);
        }
        public async Task GetAllShouldReturnExactlyTheSameUsers(int usersCount)
        {
            //Arrange
            var expectedUsers   = Fakers.User.Generate(usersCount);
            var usersRepository = A.Fake <IUsersRepository>();

            A.CallTo(() => usersRepository.GetUsersAsync()).Returns(expectedUsers);
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => usersRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.GetSuccessAsync("/api/v1/users");

            var users = JsonSerializer.Deserialize <JeevesUser[]>(await response.Content.ReadAsStringAsync());

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.OK);
            users.Should().BeEquivalentTo(expectedUsers);
        }
        public async Task GetByIdShouldReturnSpecifiedAttempt(int attemptNumber)
        {
            //Arrange
            var attempts           = Fakers.Attempt.Generate(10);
            var expectedAttempt    = attempts[attemptNumber];
            var attemptsRepository = A.Fake <IAttemptsRepository>();

            A.CallTo(() => attemptsRepository.FindAttemptAsync(expectedAttempt.Id)).Returns(expectedAttempt);
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => attemptsRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.GetSuccessAsync($"/api/v1/challenges/{Guid.NewGuid()}/attempts/{expectedAttempt.Id}");

            var attempt = JsonSerializer.Deserialize <JeevesAttempt>(await response.Content.ReadAsStringAsync());

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.OK);
            attempt.Should().BeEquivalentTo(expectedAttempt);
        }
        public async Task PostShouldReturnCreatedStatusCode()
        {
            //Arrange
            var user            = Fakers.User.Generate();
            var usersRepository = A.Fake <IUsersRepository>();

            A.CallTo(() => usersRepository.CreateUserAsync(A <User> .Ignored)).Returns(Task.FromResult(user));
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => usersRepository));
            using var client  = factory.CreateClient();
            var createUserRequest = new CreateUser {
                FirstName = user.FirstName, LastName = user.LastName
            };

            //Act
            using var response = await client.PostAsync("/api/v1/users/", JsonSerializer.Serialize(createUserRequest));

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.Created);
            response.Headers.Location.PathAndQuery.Should().Be($"/api/v1/users/{user.Id}");
        }
        public async Task GetByIdShouldReturnSpecifiedUser(int userNumber)
        {
            //Arrange
            var users           = Fakers.User.Generate(10);
            var expectedUser    = users[userNumber];
            var usersRepository = A.Fake <IUsersRepository>();

            A.CallTo(() => usersRepository.FindUserAsync(expectedUser.Id)).Returns(expectedUser);
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => usersRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.GetSuccessAsync($"/api/v1/users/{expectedUser.Id}");

            var user = JsonSerializer.Deserialize <JeevesUser>(await response.Content.ReadAsStringAsync());

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.OK);
            user.Should().BeEquivalentTo(expectedUser);
        }
        public async Task PostShouldReturnCreatedStatusCode()
        {
            //Arrange
            var challenge            = Fakers.Challenge.Generate();
            var challengesRepository = A.Fake <IChallengesRepository>();

            A.CallTo(() => challengesRepository.CreateChallengeAsync(A <Challenge> .Ignored)).Returns(Task.FromResult(challenge));
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => challengesRepository));
            using var client  = factory.CreateClient();
            var createChallengeRequest = new CreateChallenge()
            {
                Name = challenge.Name
            };

            //Act
            using var response = await client.PostAsync("/api/v1/challenges/", JsonSerializer.Serialize(createChallengeRequest));

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.Created);
            response.Headers.Location.PathAndQuery.Should().Be($"/api/v1/challenges/{challenge.Id}");
        }
        public async Task DeleteByIdShouldDeleteSpecifiedUser(int userNumber)
        {
            //Arrange
            var users           = Fakers.User.Generate(10);
            var deletedUser     = users[userNumber];
            var usersRepository = A.Fake <IUsersRepository>();

            A.CallTo(() => usersRepository.DeleteUserAsync(deletedUser.Id)).ReturnsLazily(() => Task.FromResult(users.Remove(deletedUser)));
            A.CallTo(() => usersRepository.FindUserAsync(deletedUser.Id)).ReturnsLazily(() => Task.FromResult(users.Find(u => u.Id == deletedUser.Id)));
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => usersRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.DeleteAsync($"/api/v1/users/{deletedUser.Id}");

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.NoContent);
            using var getResponse = await client.GetAsync($"/api/v1/users/{deletedUser.Id}");

            getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
        }
        public async Task DeleteByIdShouldDeleteSpecifiedAttempt(int attemptNumber)
        {
            //Arrange
            var attempts           = Fakers.Attempt.Generate(10);
            var deletedAttempt     = attempts[attemptNumber];
            var attemptsRepository = A.Fake <IAttemptsRepository>();

            A.CallTo(() => attemptsRepository.DeleteAttemptAsync(deletedAttempt.Id)).ReturnsLazily(() => Task.FromResult(attempts.Remove(deletedAttempt)));
            A.CallTo(() => attemptsRepository.FindAttemptAsync(deletedAttempt.Id)).ReturnsLazily(() => Task.FromResult(attempts.Find(u => u.Id == deletedAttempt.Id)));
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => attemptsRepository));
            using var client  = factory.CreateClient();

            //Act
            using var response = await client.DeleteAsync($"/api/v1/challenges/{Guid.NewGuid()}/attempts/{deletedAttempt.Id}");

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.NoContent);
            using var getResponse = await client.GetAsync($"/api/v1/challenges/{Guid.NewGuid()}/attempts/{deletedAttempt.Id}");

            getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
        }
        public async Task PostShouldReturnCreatedStatusCode()
        {
            //Arrange
            var attempt            = Fakers.Attempt.Generate();
            var challengeId        = Guid.NewGuid();
            var attemptsRepository = A.Fake <IAttemptsRepository>();

            A.CallTo(() => attemptsRepository.CreateAttemptAsync(A <ChallengeAttempt> .Ignored)).Returns(Task.FromResult(attempt));
            using var factory = new JeevesWebApplicationFactory(services => services.SwapSingleton(provider => attemptsRepository));
            using var client  = factory.CreateClient();
            var createAttemptRequest = new CreateAttempt()
            {
                Solution = new byte[0]
            };

            //Act
            using var response = await client.PostAsync($"/api/v1/challenges/{challengeId}/attempts", JsonSerializer.Serialize(createAttemptRequest));

            //Assert
            response.StatusCode.Should().Be(HttpStatusCode.Created);
            response.Headers.Location.PathAndQuery.Should().Be($"/api/v1/challenges/{challengeId}/attempts/{attempt.Id}");
        }