/* * 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 System; using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Settings.Logging; namespace SafeExamBrowser.Logging.UnitTests { [TestClass] public class LoggerTests { [TestMethod] public void MustAddMessagesToLog() { var sut = new Logger(); var debug = "I'm a debug message"; var info = "I'm an info message"; var warn = "I'm a warning!"; var error = "I AM AN ERROR!!"; var exceptionMessage = "I'm an exception message"; var exception = new Exception(exceptionMessage); var message = "I'm a simple text message"; sut.Debug(debug); sut.Info(info); sut.Warn(warn); sut.Error(error); sut.Error(error, exception); sut.Log(message); var log = sut.GetLog(); Assert.HasCount(7, log); Assert.IsTrue(debug.Equals((log[0] as ILogMessage).Message)); Assert.AreEqual(LogLevel.Debug, (log[0] as ILogMessage).Severity); Assert.IsTrue(info.Equals((log[1] as ILogMessage).Message)); Assert.AreEqual(LogLevel.Info, (log[1] as ILogMessage).Severity); Assert.IsTrue(warn.Equals((log[2] as ILogMessage).Message)); Assert.AreEqual(LogLevel.Warning, (log[2] as ILogMessage).Severity); Assert.IsTrue(error.Equals((log[3] as ILogMessage).Message)); Assert.AreEqual(LogLevel.Error, (log[3] as ILogMessage).Severity); Assert.IsTrue(error.Equals((log[4] as ILogMessage).Message)); Assert.AreEqual(LogLevel.Error, (log[4] as ILogMessage).Severity); Assert.Contains(exceptionMessage, (log[5] as ILogText).Text); Assert.IsTrue(message.Equals((log[6] as ILogText).Text)); } [TestMethod] public void MustAddInnerExceptionsToLog() { var sut = new Logger(); var outerMessage = "Some message for the outer exception"; var innerMessage = "BAAAAM! Inner one here."; var innerInnerMessage = "Yikes, a null reference..."; var exception = new Exception(outerMessage, new ArgumentException(innerMessage, new NullReferenceException(innerInnerMessage))); sut.Error("blubb", exception); var log = sut.GetLog(); var logText = log[1] as ILogText; Assert.HasCount(2, log); Assert.Contains(outerMessage, logText.Text); Assert.Contains(innerMessage, logText.Text); Assert.Contains(innerInnerMessage, logText.Text); } [TestMethod] public void MustReturnCopyOfLog() { var sut = new Logger(); var debug = "I'm a debug message"; var info = "I'm an info message"; var warn = "I'm a warning!"; var error = "I AM AN ERROR!!"; sut.Debug(debug); sut.Info(info); sut.Warn(warn); sut.Error(error); var log1 = sut.GetLog(); var log2 = sut.GetLog(); Assert.AreNotSame(log1, log2); foreach (var message in log1) { Assert.AreNotSame(message, log2[log1.IndexOf(message)]); } } [TestMethod] public void MustNotAllowLoggingNull() { var sut = new Logger(); Assert.ThrowsExactly(() => sut.Debug(null)); Assert.ThrowsExactly(() => sut.Info(null)); Assert.ThrowsExactly(() => sut.Warn(null)); Assert.ThrowsExactly(() => sut.Error(null)); Assert.ThrowsExactly(() => sut.Error(null, null)); Assert.ThrowsExactly(() => sut.Error("Hello world!", null)); Assert.ThrowsExactly(() => sut.Error(null, new Exception())); Assert.ThrowsExactly(() => sut.Log((string) null)); } [TestMethod] public void MustNotAllowNullObserver() { var sut = new Logger(); Assert.ThrowsExactly(() => sut.Subscribe(null)); } [TestMethod] public void MustNotSubscribeSameObserverMultipleTimes() { var sut = new Logger(); var observer = new Mock(); observer.Setup(o => o.Notify(It.IsAny())); sut.Subscribe(observer.Object); sut.Subscribe(observer.Object); sut.Subscribe(observer.Object); sut.Info("Blubb"); observer.Verify(o => o.Notify(It.IsAny()), Times.Once()); } [TestMethod] public void MustNotFailWhenRemovingNullObserver() { var sut = new Logger(); sut.Unsubscribe(null); } [TestMethod] public void MustSubscribeObserver() { var sut = new Logger(); var observer = new Mock(); var message = "Blubb"; var messages = new List(); observer.Setup(o => o.Notify(It.IsAny())).Callback(m => messages.Add(m)); sut.Subscribe(observer.Object); sut.Info(message); sut.Warn(message); observer.Verify(o => o.Notify(It.IsAny()), Times.Exactly(2)); Assert.HasCount(2, messages); Assert.AreEqual(LogLevel.Info, (messages[0] as ILogMessage).Severity); Assert.IsTrue(message.Equals((messages[0] as ILogMessage).Message)); Assert.AreEqual(LogLevel.Warning, (messages[1] as ILogMessage).Severity); Assert.IsTrue(message.Equals((messages[1] as ILogMessage).Message)); } [TestMethod] public void MustRespectLogLevel() { var sut = new Logger(); sut.LogLevel = LogLevel.Error; sut.Debug("debug"); sut.Info("info"); sut.Warn("warn"); Assert.IsEmpty(sut.GetLog()); sut = new Logger(); sut.LogLevel = LogLevel.Warning; sut.Debug("debug"); sut.Info("info"); sut.Warn("warn"); Assert.HasCount(1, sut.GetLog()); sut = new Logger(); sut.LogLevel = LogLevel.Info; sut.Debug("debug"); sut.Info("info"); sut.Warn("warn"); Assert.HasCount(2, sut.GetLog()); sut = new Logger(); sut.LogLevel = LogLevel.Debug; sut.Debug("debug"); sut.Info("info"); sut.Warn("warn"); Assert.HasCount(3, sut.GetLog()); } [TestMethod] public void MustUnsubscribeObserver() { var sut = new Logger(); var observer = new Mock(); var message = "Blubb"; var messages = new List(); observer.Setup(o => o.Notify(It.IsAny())).Callback(m => messages.Add(m)); sut.Subscribe(observer.Object); sut.Info(message); sut.Unsubscribe(observer.Object); sut.Warn(message); observer.Verify(o => o.Notify(It.IsAny()), Times.Once()); Assert.HasCount(1, messages); Assert.AreEqual(LogLevel.Info, (messages[0] as ILogMessage).Severity); Assert.IsTrue(message.Equals((messages[0] as ILogMessage).Message)); } } }