public async Task Index_ExecutedWithNoOutstandingAgreementsAndNoContextWithNonLocalRedirectUrl_ThrowsException()
        {
            //Arrange
            var id = Guid.NewGuid().ToString();

            using var termsOfServiceController = new TermsOfServiceController(fakeUserManager, termsOfServiceRepository, mockConfiguration, mockIdentityServerInteractionService,
                                                                              mockEventService, mockClientStore, fakeSignInManager)
                  {
                      ControllerContext = new ControllerContext()
                      {
                          HttpContext = new DefaultHttpContext()
                          {
                              User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
                        {
                            new Claim(ClaimTypes.Name, "example name"),
                            new Claim(ClaimTypes.NameIdentifier, id),
                            new Claim("sub", id),
                            new Claim("custom-claim", "example claim value"),
                        }, "mock")),
                          }
                      }
                  };

            fakeUserManager.SetUserModel(userModel);
            termsOfServiceRepository.GetAllOutstandingAgreementsByUserAsync(Arg.Any <Guid>()).Returns(new List <Guid>());

            var builder = new ConfigurationBuilder()
                          .SetBasePath(Directory.GetCurrentDirectory())
                          .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                          .AddEnvironmentVariables();

            var config = builder.Build();

            config.GetSection("TwoFactorAuthentication")["OrganizationEnforced"] = "false";
            config.GetSection("TwoFactorAuthentication")["AuthenticatorEnabled"] = "false";
            mockConfiguration.GetSection("TwoFactorAuthentication").Returns(config.GetSection("TwoFactorAuthentication"));

            var urlHelper = Substitute.For <IUrlHelper>();

            urlHelper.IsLocalUrl(Arg.Any <string>()).Returns(false);
            termsOfServiceController.Url = urlHelper;

            // Act
            try
            {
                var actionResult = await termsOfServiceController.Index(returnUrl : "http://www.test.me/redirect", 0);

                // Assert
                Assert.True(false, "Non-local redirect with no context must throw Exception.");
            }
            catch
            {
                // Assert
                Assert.True(true, "Non-local redirect with no context must throw Exception.");
            }
        }
        public async Task Index_ExecutedWithNoOutstandingAgreementsAndIsPkceClient_ViewResultReturned()
        {
            //Arrange
            var id = Guid.NewGuid().ToString();

            using var termsOfServiceController = new TermsOfServiceController(fakeUserManager, termsOfServiceRepository, mockConfiguration, mockIdentityServerInteractionService,
                                                                              mockEventService, mockClientStore, fakeSignInManager)
                  {
                      ControllerContext = new ControllerContext()
                      {
                          HttpContext = new DefaultHttpContext()
                          {
                              User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
                        {
                            new Claim(ClaimTypes.Name, "example name"),
                            new Claim(ClaimTypes.NameIdentifier, id),
                            new Claim("sub", id),
                            new Claim("custom-claim", "example claim value"),
                        }, "mock")),
                          }
                      }
                  };

            fakeUserManager.SetUserModel(userModel);
            termsOfServiceRepository.GetAllOutstandingAgreementsByUserAsync(Arg.Any <Guid>()).Returns(new List <Guid>());

            var builder = new ConfigurationBuilder()
                          .SetBasePath(Directory.GetCurrentDirectory())
                          .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                          .AddEnvironmentVariables();

            var config = builder.Build();

            config.GetSection("TwoFactorAuthentication")["OrganizationEnforced"] = "false";
            config.GetSection("TwoFactorAuthentication")["AuthenticatorEnabled"] = "false";
            mockConfiguration.GetSection("TwoFactorAuthentication").Returns(config.GetSection("TwoFactorAuthentication"));

            mockIdentityServerInteractionService.GetAuthorizationContextAsync(Arg.Any <string>()).Returns(authorizationRequest);

            client.RequirePkce = true;
            mockClientStore.FindEnabledClientByIdAsync(Arg.Any <string>()).Returns(client);

            // Act
            var actionResult = await termsOfServiceController.Index(RETURN_URL, 0);

            // Assert
            var viewResult = actionResult as ViewResult;

            Assert.NotNull(viewResult);
            Assert.True(viewResult.ViewName == "Redirect", $"ViewName must be 'Redirect'.");

            var model = viewResult.Model as RedirectViewModel;

            Assert.True(model.RedirectUrl == RETURN_URL, $"Redirect Url must be '{RETURN_URL}'.");
        }
        public async Task Index_PostExecutedWithUnAcceptedTermsOfServiceAndIsPkceClient_ViewResultReturned()
        {
            //Arrange
            var id = Guid.NewGuid().ToString();

            using var termsOfServiceController = new TermsOfServiceController(fakeUserManager, termsOfServiceRepository, mockConfiguration, mockIdentityServerInteractionService,
                                                                              mockEventService, mockClientStore, fakeSignInManager)
                  {
                      ControllerContext = new ControllerContext()
                      {
                          HttpContext = new DefaultHttpContext()
                          {
                              User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
                        {
                            new Claim(ClaimTypes.Name, "example name"),
                            new Claim(ClaimTypes.NameIdentifier, id),
                            new Claim("sub", id),
                            new Claim("custom-claim", "example claim value"),
                        }, "mock")),
                          }
                      }
                  };

            fakeUserManager.SetUserModel(userModel);

            var termOfServiceId          = Guid.NewGuid();
            var termsOfServiceInputModel = new TermsOfServiceInputModel()
            {
                Accepted = false,
                InitialAgreementCount = 3,
                ReturnUrl             = RETURN_URL,
                TermsOfServiceId      = termOfServiceId
            };

            mockIdentityServerInteractionService.GetAuthorizationContextAsync(Arg.Any <string>()).Returns(authorizationRequest);

            client.RequirePkce = true;
            mockClientStore.FindEnabledClientByIdAsync(Arg.Any <string>()).Returns(client);

            // Act
            var actionResult = await termsOfServiceController.Index(termsOfServiceInputModel, "accept", RETURN_URL);

            // Assert
            var viewResult = actionResult as ViewResult;

            Assert.NotNull(viewResult);

            var model = viewResult.Model as RedirectViewModel;

            Assert.NotNull(model);
            Assert.True(model.RedirectUrl == RETURN_URL, $"Redirect URL must be '{RETURN_URL}'.");
        }
        public async Task Index_PostExecutedWithInvalidUserContext_ThrowsAuthenticationException()
        {
            //Arrange
            var id = Guid.NewGuid().ToString();

            using var termsOfServiceController = new TermsOfServiceController(fakeUserManager, termsOfServiceRepository, mockConfiguration, mockIdentityServerInteractionService,
                                                                              mockEventService, mockClientStore, fakeSignInManager)
                  {
                      ControllerContext = new ControllerContext()
                      {
                          HttpContext = new DefaultHttpContext()
                          {
                              User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
                        {
                            new Claim(ClaimTypes.Name, "example name"),
                            new Claim(ClaimTypes.NameIdentifier, id),
                            new Claim("sub", id),
                            new Claim("custom-claim", "example claim value"),
                        }, "mock")),
                          }
                      }
                  };

            fakeUserManager.SetUserModel(null);

            var termOfServiceId          = Guid.NewGuid();
            var termsOfServiceInputModel = new TermsOfServiceInputModel()
            {
                Accepted = true,
                InitialAgreementCount = 3,
                ReturnUrl             = RETURN_URL,
                TermsOfServiceId      = termOfServiceId
            };

            Exception caughtException = null;

            try
            {
                var actionResult = await termsOfServiceController.Index(termsOfServiceInputModel, "accept", RETURN_URL);
            }
            catch (Exception ex)
            {
                caughtException = ex;
            }

            // Assert
            Assert.True(caughtException is AuthenticationException, "Invalid login data must throw an AuthenticationException.");
        }
        public async Task Index_PostExecutedWithAcceptedTermsOfService_ViewResultReturned()
        {
            //Arrange
            var id = Guid.NewGuid().ToString();

            using var termsOfServiceController = new TermsOfServiceController(fakeUserManager, termsOfServiceRepository, mockConfiguration, mockIdentityServerInteractionService,
                                                                              mockEventService, mockClientStore, fakeSignInManager)
                  {
                      ControllerContext = new ControllerContext()
                      {
                          HttpContext = new DefaultHttpContext()
                          {
                              User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
                        {
                            new Claim(ClaimTypes.Name, "example name"),
                            new Claim(ClaimTypes.NameIdentifier, id),
                            new Claim("sub", id),
                            new Claim("custom-claim", "example claim value"),
                        }, "mock")),
                          }
                      }
                  };

            fakeUserManager.SetUserModel(userModel);

            var termOfServiceId          = Guid.NewGuid();
            var termsOfServiceInputModel = new TermsOfServiceInputModel()
            {
                Accepted = true,
                InitialAgreementCount = 3,
                ReturnUrl             = RETURN_URL,
                TermsOfServiceId      = termOfServiceId
            };

            // Act
            var actionResult = await termsOfServiceController.Index(termsOfServiceInputModel, "accept", RETURN_URL);

            // Assert
            var viewResult = actionResult as RedirectToActionResult;

            Assert.NotNull(viewResult);
            Assert.True(viewResult.ActionName == "Index", "Redirect action must be 'Index'.");
            Assert.True(viewResult.RouteValues.Count == 2, "Route value count must be 2.");
            Assert.True(viewResult.RouteValues["returnUrl"].ToString() == RETURN_URL, $"Route value 'returnUrl' must be '{RETURN_URL}'.");
            Assert.True(viewResult.RouteValues["initialAgreementCount"].ToString() == "3", $"Route value 'returnUrl' must be '3'.");
        }
        public async Task Index_ExecutedWithOutstandingAgreementsButUnfindableAgreementGuid_ThrowsItemNotFoundException()
        {
            //Arrange
            var id = Guid.NewGuid().ToString();

            using var termsOfServiceController = new TermsOfServiceController(fakeUserManager, termsOfServiceRepository, mockConfiguration, mockIdentityServerInteractionService,
                                                                              mockEventService, mockClientStore, fakeSignInManager)
                  {
                      ControllerContext = new ControllerContext()
                      {
                          HttpContext = new DefaultHttpContext()
                          {
                              User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
                        {
                            new Claim(ClaimTypes.Name, "example name"),
                            new Claim(ClaimTypes.NameIdentifier, id),
                            new Claim("sub", id),
                            new Claim("custom-claim", "example claim value"),
                        }, "mock")),
                          }
                      }
                  };

            fakeUserManager.SetUserModel(userModel);
            termsOfServiceRepository.GetAllOutstandingAgreementsByUserAsync(Arg.Any <Guid>())
            .Returns(new List <Guid>()
            {
                Guid.NewGuid(),
                Guid.NewGuid()
            });

            // Act
            Exception caughtException = null;

            try
            {
                var actionResult = await termsOfServiceController.Index(RETURN_URL, 0);
            }
            catch (Exception ex)
            {
                caughtException = ex;
            }

            // Assert
            Assert.True(caughtException is ItemNotFoundException, "Caught exception must be sItemNotFoundException.");
        }
        public async Task Index_ExecutedWithOutstandingAgreements_ViewResultReturned()
        {
            //Arrange
            var id = Guid.NewGuid().ToString();

            using var termsOfServiceController = new TermsOfServiceController(fakeUserManager, termsOfServiceRepository, mockConfiguration, mockIdentityServerInteractionService,
                                                                              mockEventService, mockClientStore, fakeSignInManager)
                  {
                      ControllerContext = new ControllerContext()
                      {
                          HttpContext = new DefaultHttpContext()
                          {
                              User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
                        {
                            new Claim(ClaimTypes.Name, "example name"),
                            new Claim(ClaimTypes.NameIdentifier, id),
                            new Claim("sub", id),
                            new Claim("custom-claim", "example claim value"),
                        }, "mock")),
                          }
                      }
                  };

            fakeUserManager.SetUserModel(userModel);
            termsOfServiceRepository.GetAllOutstandingAgreementsByUserAsync(Arg.Any <Guid>())
            .Returns(new List <Guid>()
            {
                Guid.NewGuid(),
                Guid.NewGuid()
            });

            termsOfServiceRepository.GetByIdAsync(Arg.Any <Guid>(), Arg.Any <bool>(), Arg.Any <bool>()).Returns(termsOfServiceModel);

            // Act
            var actionResult = await termsOfServiceController.Index(RETURN_URL, 0);

            // Assert
            var viewResult = actionResult as ViewResult;

            Assert.NotNull(viewResult);

            var model = viewResult.Model as TermsOfServiceViewModel;

            Assert.True(model.AgreementName == termsOfServiceModel.AgreementName, $"Model field AgreementName '{model.AgreementName}' should be '{termsOfServiceModel.AgreementName}'.");
            Assert.True(model.AgreementCount == 2, $"Model field AgreementCount '{model.AgreementCount}' should be '2'.");
        }