public async void ShouldThrowValidationExceptionOnRegisterWhenCreatedDateIsNotRecentAndLogItAsync(
            int minutes)
        {
            // given
            DateTimeOffset randomDate     = GetRandomDateTime();
            Student        randomStudent  = CreateRandomStudent(randomDate);
            Student        invalidStudent = randomStudent;

            invalidStudent.CreatedDate = randomDate.AddMinutes(minutes);
            invalidStudent.UpdatedDate = invalidStudent.CreatedDate;

            var invalidStudentException = new InvalidStudentException();

            invalidStudentException.AddData(
                key: nameof(Student.CreatedDate),
                values: $"Date is not recent");

            var expectedStudentValidationException =
                new StudentValidationException(invalidStudentException);

            this.dateTimeBrokerMock.Setup(broker =>
                                          broker.GetCurrentDateTime())
            .Returns(randomDate);

            // when
            ValueTask <Student> registerStudentTask =
                this.studentService.RegisterStudentAsync(invalidStudent);

            // then
            await Assert.ThrowsAsync <StudentValidationException>(() =>
                                                                  registerStudentTask.AsTask());

            this.dateTimeBrokerMock.Verify(broker =>
                                           broker.GetCurrentDateTime(),
                                           Times.Once);

            this.loggingBrokerMock.Verify(broker =>
                                          broker.LogError(It.Is(SameValidationExceptionAs(
                                                                    expectedStudentValidationException))),
                                          Times.Once);

            this.storageBrokerMock.Verify(broker =>
                                          broker.InsertStudentAsync(It.IsAny <Student>()),
                                          Times.Never);

            this.dateTimeBrokerMock.VerifyNoOtherCalls();
            this.loggingBrokerMock.VerifyNoOtherCalls();
            this.storageBrokerMock.VerifyNoOtherCalls();
        }
        public async Task ShouldThrowValidationExceptionOnModifyIfCreatedAndUpdatedDatesAreSameAndLogItAsync()
        {
            // given
            Student        randomStudent  = CreateRandomStudent();
            DateTimeOffset sameDate       = randomStudent.CreatedDate;
            Student        invalidStudent = randomStudent;

            invalidStudent.CreatedDate = sameDate;
            invalidStudent.UpdatedDate = sameDate;
            var invalidStudentException = new InvalidStudentException();

            invalidStudentException.AddData(
                key: nameof(Student.UpdatedDate),
                values: $"Date is the same as {nameof(Student.CreatedDate)}");

            var expectedStudentValidationException =
                new StudentValidationException(invalidStudentException);

            this.dateTimeBrokerMock.Setup(broker =>
                                          broker.GetCurrentDateTime())
            .Returns(DateTimeOffset.UtcNow);

            // when
            ValueTask <Student> modifyStudentTask =
                this.studentService.ModifyStudentAsync(invalidStudent);

            // then
            await Assert.ThrowsAsync <StudentValidationException>(() =>
                                                                  modifyStudentTask.AsTask());

            this.dateTimeBrokerMock.Verify(broker =>
                                           broker.GetCurrentDateTime(),
                                           Times.Once);

            this.loggingBrokerMock.Verify(broker =>
                                          broker.LogError(It.Is(SameValidationExceptionAs(
                                                                    expectedStudentValidationException))),
                                          Times.Once);

            this.loggingBrokerMock.VerifyNoOtherCalls();
            this.storageBrokerMock.VerifyNoOtherCalls();
            this.dateTimeBrokerMock.VerifyNoOtherCalls();
        }
        public async Task ShouldThrowValidationExceptionOnModifyIfStudentUpdatedDateIsNotRecentAndLogItAsync(
            int randomMoreOrLessThanOneMinute)
        {
            // given
            DateTimeOffset randomDateTime = GetRandomDateTime();
            Student        randomStudent  = CreateRandomStudent(dates: randomDateTime);
            Student        invalidStudent = randomStudent;

            invalidStudent.UpdatedDate =
                invalidStudent.UpdatedDate.AddMinutes(randomMoreOrLessThanOneMinute);

            var invalidStudentException = new InvalidStudentException();

            invalidStudentException.AddData(
                key: nameof(Student.UpdatedDate),
                values: "Date is not recent");

            var expectedStudentValidationException =
                new StudentValidationException(invalidStudentException);

            // when
            ValueTask <Student> modifyStudentTask =
                this.studentService.ModifyStudentAsync(invalidStudent);

            // then
            await Assert.ThrowsAsync <StudentValidationException>(() =>
                                                                  modifyStudentTask.AsTask());

            this.dateTimeBrokerMock.Verify(broker =>
                                           broker.GetCurrentDateTime(),
                                           Times.Once);

            this.loggingBrokerMock.Verify(broker =>
                                          broker.LogError(It.Is(SameValidationExceptionAs(
                                                                    expectedStudentValidationException))),
                                          Times.Once);

            this.loggingBrokerMock.VerifyNoOtherCalls();
            this.storageBrokerMock.VerifyNoOtherCalls();
            this.dateTimeBrokerMock.VerifyNoOtherCalls();
        }
        public async Task ShouldThrowValidationExceptionOnModifyWhenStudentIsInvalidAndLogItAsync(string invalidText)
        {
            // given
            var invalidStudent = new Student
            {
                UserId         = invalidText,
                IdentityNumber = invalidText,
                FirstName      = invalidText,
            };

            var invalidStudentException = new InvalidStudentException();

            invalidStudentException.AddData(
                key: nameof(Student.Id),
                values: "Id is required");

            invalidStudentException.AddData(
                key: nameof(Student.UserId),
                values: "Text is required");

            invalidStudentException.AddData(
                key: nameof(Student.IdentityNumber),
                values: "Text is required");

            invalidStudentException.AddData(
                key: nameof(Student.FirstName),
                values: "Text is required");

            invalidStudentException.AddData(
                key: nameof(Student.BirthDate),
                values: "Date is required");

            invalidStudentException.AddData(
                key: nameof(Student.CreatedBy),
                values: "Id is required");

            invalidStudentException.AddData(
                key: nameof(Student.UpdatedBy),
                values: "Id is required");

            invalidStudentException.AddData(
                key: nameof(Student.CreatedDate),
                values: "Date is required");

            invalidStudentException.AddData(
                key: nameof(Student.UpdatedDate),
                "Date is required",
                $"Date is the same as {nameof(Student.CreatedDate)}");

            var expectedStudentValidationException =
                new StudentValidationException(invalidStudentException);

            // when
            ValueTask <Student> modifyStudentTask =
                this.studentService.ModifyStudentAsync(invalidStudent);

            // then
            await Assert.ThrowsAsync <StudentValidationException>(() =>
                                                                  modifyStudentTask.AsTask());

            this.dateTimeBrokerMock.Verify(broker =>
                                           broker.GetCurrentDateTime(),
                                           Times.Once);

            this.loggingBrokerMock.Verify(broker =>
                                          broker.LogError(It.Is(SameValidationExceptionAs(expectedStudentValidationException))),
                                          Times.Once);

            this.storageBrokerMock.Verify(broker =>
                                          broker.UpdateStudentAsync(It.IsAny <Student>()),
                                          Times.Never);

            this.dateTimeBrokerMock.VerifyNoOtherCalls();
            this.loggingBrokerMock.VerifyNoOtherCalls();
            this.storageBrokerMock.VerifyNoOtherCalls();
        }
        ShouldThrowValidationExceptionOnModifyIfStorageStudentAuditInformationNotSameAsInputStudentAuditInformationAndLogItAsync()
        {
            // given
            int            randomNumber     = GetRandomNumber();
            DateTimeOffset randomDate       = GetRandomDateTime();
            Guid           differentId      = Guid.NewGuid();
            Guid           invalidCreatedBy = differentId;
            Student        randomStudent    = CreateRandomStudent(dates: randomDate);
            Student        invalidStudent   = randomStudent;
            Student        storageStudent   = randomStudent.DeepClone();

            invalidStudent.CreatedDate = storageStudent.CreatedDate.AddDays(randomNumber);
            invalidStudent.UpdatedDate = storageStudent.UpdatedDate;
            invalidStudent.CreatedBy   = invalidCreatedBy;
            Guid studentId = invalidStudent.Id;

            var invalidStudentException = new InvalidStudentException();

            invalidStudentException.AddData(
                key: nameof(Student.CreatedDate),
                values: $"Date is not the same as {nameof(Student.CreatedDate)}");
            invalidStudentException.AddData(
                key: nameof(Student.UpdatedDate),
                values: $"Date is same as {nameof(Student.UpdatedDate)}");
            invalidStudentException.AddData(
                key: nameof(Student.CreatedBy),
                values: $"Id is not the same as {nameof(Student.CreatedBy)}");

            var expectedStudentValidationException =
                new StudentValidationException(invalidStudentException);

            this.storageBrokerMock.Setup(broker =>
                                         broker.SelectStudentByIdAsync(studentId))
            .ReturnsAsync(storageStudent);

            this.dateTimeBrokerMock.Setup(broker =>
                                          broker.GetCurrentDateTime())
            .Returns(randomDate);

            // when
            ValueTask <Student> modifyStudentTask =
                this.studentService.ModifyStudentAsync(invalidStudent);

            // then
            await Assert.ThrowsAsync <StudentValidationException>(() =>
                                                                  modifyStudentTask.AsTask());

            this.dateTimeBrokerMock.Verify(broker =>
                                           broker.GetCurrentDateTime(),
                                           Times.Once);

            this.storageBrokerMock.Verify(broker =>
                                          broker.SelectStudentByIdAsync(invalidStudent.Id),
                                          Times.Once);

            this.loggingBrokerMock.Verify(broker =>
                                          broker.LogError(It.Is(SameExceptionAs(expectedStudentValidationException))),
                                          Times.Once);

            this.loggingBrokerMock.VerifyNoOtherCalls();
            this.storageBrokerMock.VerifyNoOtherCalls();
            this.dateTimeBrokerMock.VerifyNoOtherCalls();
        }