/* * Copyright (c) 2025 ETH Zürich, IT Services * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Client.Responsibilities; using SafeExamBrowser.Communication.Contracts.Proxies; using SafeExamBrowser.Configuration.Contracts.Cryptography; using SafeExamBrowser.Core.Contracts.ResponsibilityModel; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Settings; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.MessageBox; using SafeExamBrowser.UserInterface.Contracts.Shell; using SafeExamBrowser.UserInterface.Contracts.Windows; using SafeExamBrowser.UserInterface.Contracts.Windows.Data; namespace SafeExamBrowser.Client.UnitTests.Responsibilities { [TestClass] public class ShellResponsibilityTests { private Mock actionCenter; private ClientContext context; private Mock hashAlgorithm; private Mock messageBox; private Mock runtime; private AppSettings settings; private Mock taskbar; private Mock uiFactory; private ShellResponsibility sut; [TestInitialize] public void Initialize() { var logger = new Mock(); var responsibilities = new Mock>(); actionCenter = new Mock(); context = new ClientContext(); hashAlgorithm = new Mock(); messageBox = new Mock(); runtime = new Mock(); settings = new AppSettings(); taskbar = new Mock(); uiFactory = new Mock(); context.MessageBox = messageBox.Object; context.Responsibilities = responsibilities.Object; context.Runtime = runtime.Object; context.Settings = settings; sut = new ShellResponsibility( actionCenter.Object, context, hashAlgorithm.Object, logger.Object, messageBox.Object, taskbar.Object, uiFactory.Object); sut.Assume(ClientTask.RegisterEvents); } [TestMethod] public void Shutdown_MustAskUserToConfirm() { var args = new System.ComponentModel.CancelEventArgs(); messageBox.Setup(m => m.Show( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(MessageBoxResult.Yes); runtime.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true)); taskbar.Raise(t => t.QuitButtonClicked += null, args as object); runtime.Verify(p => p.RequestShutdown(), Times.Once); Assert.IsFalse(args.Cancel); } [TestMethod] public void Shutdown_MustNotInitiateIfNotWishedByUser() { var args = new System.ComponentModel.CancelEventArgs(); messageBox.Setup(m => m.Show( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(MessageBoxResult.No); taskbar.Raise(t => t.QuitButtonClicked += null, args as object); runtime.Verify(p => p.RequestShutdown(), Times.Never); Assert.IsTrue(args.Cancel); } [TestMethod] public void Shutdown_MustCloseActionCenterAndTaskbarIfEnabled() { settings.UserInterface.ActionCenter.EnableActionCenter = true; settings.UserInterface.Taskbar.EnableTaskbar = true; sut.Assume(ClientTask.CloseShell); actionCenter.Verify(a => a.Close(), Times.Once); taskbar.Verify(o => o.Close(), Times.Once); } [TestMethod] public void Shutdown_MustNotCloseActionCenterAndTaskbarIfNotEnabled() { settings.UserInterface.ActionCenter.EnableActionCenter = false; settings.UserInterface.Taskbar.EnableTaskbar = false; sut.Assume(ClientTask.CloseShell); actionCenter.Verify(a => a.Close(), Times.Never); taskbar.Verify(o => o.Close(), Times.Never); } [TestMethod] public void Shutdown_MustShowErrorMessageOnCommunicationFailure() { var args = new System.ComponentModel.CancelEventArgs(); messageBox.Setup(m => m.Show( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(MessageBoxResult.Yes); runtime.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(false)); taskbar.Raise(t => t.QuitButtonClicked += null, args as object); messageBox.Verify(m => m.Show( It.IsAny(), It.IsAny(), It.IsAny(), It.Is(i => i == MessageBoxIcon.Error), It.IsAny()), Times.Once); runtime.Verify(p => p.RequestShutdown(), Times.Once); } [TestMethod] public void Shutdown_MustAskUserForQuitPassword() { var args = new System.ComponentModel.CancelEventArgs(); var dialog = new Mock(); var dialogResult = new PasswordDialogResult { Password = "blobb", Success = true }; settings.Security.QuitPasswordHash = "1234"; dialog.Setup(d => d.Show(It.IsAny())).Returns(dialogResult); hashAlgorithm.Setup(h => h.GenerateHashFor(It.Is(s => s == dialogResult.Password))).Returns(settings.Security.QuitPasswordHash); runtime.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true)); uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny(), It.IsAny())).Returns(dialog.Object); taskbar.Raise(t => t.QuitButtonClicked += null, args as object); uiFactory.Verify(u => u.CreatePasswordDialog(It.IsAny(), It.IsAny()), Times.Once); runtime.Verify(p => p.RequestShutdown(), Times.Once); Assert.IsFalse(args.Cancel); } [TestMethod] public void Shutdown_MustAbortAskingUserForQuitPassword() { var args = new System.ComponentModel.CancelEventArgs(); var dialog = new Mock(); var dialogResult = new PasswordDialogResult { Success = false }; settings.Security.QuitPasswordHash = "1234"; dialog.Setup(d => d.Show(It.IsAny())).Returns(dialogResult); runtime.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true)); uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny(), It.IsAny())).Returns(dialog.Object); taskbar.Raise(t => t.QuitButtonClicked += null, args as object); uiFactory.Verify(u => u.CreatePasswordDialog(It.IsAny(), It.IsAny()), Times.Once); runtime.Verify(p => p.RequestShutdown(), Times.Never); Assert.IsTrue(args.Cancel); } [TestMethod] public void Shutdown_MustNotInitiateIfQuitPasswordIncorrect() { var args = new System.ComponentModel.CancelEventArgs(); var dialog = new Mock(); var dialogResult = new PasswordDialogResult { Password = "blobb", Success = true }; settings.Security.QuitPasswordHash = "1234"; dialog.Setup(d => d.Show(It.IsAny())).Returns(dialogResult); hashAlgorithm.Setup(h => h.GenerateHashFor(It.IsAny())).Returns("9876"); uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny(), It.IsAny())).Returns(dialog.Object); taskbar.Raise(t => t.QuitButtonClicked += null, args as object); messageBox.Verify(m => m.Show( It.IsAny(), It.IsAny(), It.IsAny(), It.Is(i => i == MessageBoxIcon.Warning), It.IsAny()), Times.Once); uiFactory.Verify(u => u.CreatePasswordDialog(It.IsAny(), It.IsAny()), Times.Once); runtime.Verify(p => p.RequestShutdown(), Times.Never); Assert.IsTrue(args.Cancel); } [TestMethod] public void Startup_MustCorrectlyShowTaskbar() { settings.UserInterface.Taskbar.EnableTaskbar = true; sut.Assume(ClientTask.ShowShell); taskbar.Verify(t => t.Show(), Times.Once); taskbar.Reset(); settings.UserInterface.Taskbar.EnableTaskbar = false; sut.Assume(ClientTask.ShowShell); taskbar.Verify(t => t.Show(), Times.Never); } [TestMethod] public void Startup_MustCorrectlyShowActionCenter() { settings.UserInterface.ActionCenter.EnableActionCenter = true; sut.Assume(ClientTask.ShowShell); actionCenter.Verify(t => t.Promote(), Times.Once); actionCenter.Verify(t => t.Show(), Times.Never); actionCenter.Reset(); settings.UserInterface.ActionCenter.EnableActionCenter = false; sut.Assume(ClientTask.ShowShell); actionCenter.Verify(t => t.Promote(), Times.Never); actionCenter.Verify(t => t.Show(), Times.Never); } [TestMethod] public void TerminationActivator_MustCorrectlyInitiateShutdown() { var order = 0; var pause = 0; var resume = 0; var terminationActivator = new Mock(); context.Activators.Add(terminationActivator.Object); messageBox.Setup(m => m.Show( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(MessageBoxResult.Yes); runtime.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true)); terminationActivator.Setup(t => t.Pause()).Callback(() => pause = ++order); terminationActivator.Setup(t => t.Resume()).Callback(() => resume = ++order); sut.Assume(ClientTask.RegisterEvents); terminationActivator.Raise(t => t.Activated += null); Assert.AreEqual(1, pause); Assert.AreEqual(2, resume); terminationActivator.Verify(t => t.Pause(), Times.Once); terminationActivator.Verify(t => t.Resume(), Times.Once); runtime.Verify(p => p.RequestShutdown(), Times.Once); } } }