SEBWIN-183: Refactored I18n components and extended their unit tests.
This commit is contained in:
parent
93e84b1120
commit
8be4fdda29
17 changed files with 262 additions and 25 deletions
|
@ -29,7 +29,7 @@ namespace SafeExamBrowser.Configuration
|
|||
|
||||
public bool AllowApplicationLog => true;
|
||||
public bool AllowKeyboardLayout => true;
|
||||
public string AppDataFolderName => "SafeExamBrowser";
|
||||
public string AppDataFolderName => nameof(SafeExamBrowser);
|
||||
|
||||
public string ApplicationLogFile
|
||||
{
|
||||
|
|
|
@ -10,9 +10,14 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
{
|
||||
public interface IText
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the text module, e.g. loads text data from the specified text resource.
|
||||
/// </summary>
|
||||
void Initialize(ITextResource resource);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text associated with the specified key. If the key was not found, a default text indicating
|
||||
/// that the given key is not configured shall be returned.
|
||||
/// that the given key is not configured will be returned.
|
||||
/// </summary>
|
||||
string Get(TextKey key);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
public interface ITextResource
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads all text data from a resource.
|
||||
/// Loads all text data from a resource. Throws an exception if the data could not be loaded, e.g. due to a data format error.
|
||||
/// </summary>
|
||||
IDictionary<TextKey, string> LoadText();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ using System.Collections.Generic;
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.I18n;
|
||||
|
||||
namespace SafeExamBrowser.Core.UnitTests.I18n
|
||||
|
@ -18,14 +19,18 @@ namespace SafeExamBrowser.Core.UnitTests.I18n
|
|||
[TestClass]
|
||||
public class TextTests
|
||||
{
|
||||
private Mock<ILogger> loggerMock;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
loggerMock = new Mock<ILogger>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNeverReturnNull()
|
||||
{
|
||||
var resource = new Mock<ITextResource>();
|
||||
var sut = new Text(resource.Object);
|
||||
|
||||
resource.Setup(r => r.LoadText()).Returns<IDictionary<TextKey, string>>(null);
|
||||
|
||||
var sut = new Text(loggerMock.Object);
|
||||
var text = sut.Get((TextKey)(-1));
|
||||
|
||||
Assert.IsNotNull(text);
|
||||
|
@ -35,7 +40,39 @@ namespace SafeExamBrowser.Core.UnitTests.I18n
|
|||
[ExpectedException(typeof(ArgumentNullException))]
|
||||
public void MustNotAllowNullResource()
|
||||
{
|
||||
new Text(null);
|
||||
var sut = new Text(loggerMock.Object);
|
||||
|
||||
sut.Initialize(null);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailWhenGettingNullFromResource()
|
||||
{
|
||||
var resource = new Mock<ITextResource>();
|
||||
var sut = new Text(loggerMock.Object);
|
||||
|
||||
resource.Setup(r => r.LoadText()).Returns<IDictionary<TextKey, string>>(null);
|
||||
sut.Initialize(resource.Object);
|
||||
|
||||
var text = sut.Get((TextKey)(-1));
|
||||
|
||||
Assert.IsNotNull(text);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailWhenResourceThrowsException()
|
||||
{
|
||||
var resource = new Mock<ITextResource>();
|
||||
var sut = new Text(loggerMock.Object);
|
||||
|
||||
resource.Setup(r => r.LoadText()).Throws<Exception>();
|
||||
sut.Initialize(resource.Object);
|
||||
|
||||
var text = sut.Get((TextKey)(-1));
|
||||
|
||||
loggerMock.Verify(l => l.Error(It.IsAny<string>(), It.IsAny<Exception>()), Times.AtLeastOnce);
|
||||
|
||||
Assert.IsNotNull(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Blubb>
|
||||
<ThisTagIsNotSupported>Some random text here...</ThisTagIsNotSupported>
|
||||
<NeitherIsThisOne>Bappa-dee boopa-dee</NeitherIsThisOne>
|
||||
<AnEmptyTag />
|
||||
</Blubb>
|
13
SafeExamBrowser.Core.UnitTests/I18n/Text_Invalid.txt
Normal file
13
SafeExamBrowser.Core.UnitTests/I18n/Text_Invalid.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xyzml version="1.0" encoding="utf-8" ?>
|
||||
<Blubb>
|
||||
Some random text here
|
||||
<LogWindow_Title\>>
|
||||
<Version *+()=?!
|
||||
<xml>
|
||||
Data
|
||||
</xml>
|
||||
</Blubb>
|
||||
<Blobb>
|
||||
<Blabb>
|
||||
<Bappa-dee-boopa-dee>/Bappa-dee-boopa-dee>
|
||||
</Blabb>
|
5
SafeExamBrowser.Core.UnitTests/I18n/Text_Valid.xml
Normal file
5
SafeExamBrowser.Core.UnitTests/I18n/Text_Valid.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Text>
|
||||
<LogWindow_Title>Application Log</LogWindow_Title>
|
||||
<Version>Version</Version>
|
||||
</Text>
|
75
SafeExamBrowser.Core.UnitTests/I18n/XmlTextResourceTests.cs
Normal file
75
SafeExamBrowser.Core.UnitTests/I18n/XmlTextResourceTests.cs
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* 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.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Core.I18n;
|
||||
|
||||
namespace SafeExamBrowser.Core.UnitTests.I18n
|
||||
{
|
||||
[TestClass]
|
||||
public class XmlTextResourceTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void MustCorrectlyLoadData()
|
||||
{
|
||||
var location = Assembly.GetAssembly(typeof(XmlTextResourceTests)).Location;
|
||||
var path = Path.GetDirectoryName(location) + $@"\{nameof(I18n)}\Text_Valid.xml";
|
||||
var sut = new XmlTextResource(path);
|
||||
|
||||
var text = sut.LoadText();
|
||||
|
||||
Assert.IsNotNull(text);
|
||||
Assert.IsTrue(text.Count == 2);
|
||||
Assert.AreEqual("Application Log", text[TextKey.LogWindow_Title]);
|
||||
Assert.AreEqual("Version", text[TextKey.Version]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(XmlException))]
|
||||
public void MustFailWithInvalidData()
|
||||
{
|
||||
var location = Assembly.GetAssembly(typeof(XmlTextResourceTests)).Location;
|
||||
var path = Path.GetDirectoryName(location) + $@"\{nameof(I18n)}\Text_Invalid.txt";
|
||||
var sut = new XmlTextResource(path);
|
||||
|
||||
sut.LoadText();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNeverReturnNull()
|
||||
{
|
||||
var location = Assembly.GetAssembly(typeof(XmlTextResourceTests)).Location;
|
||||
var path = Path.GetDirectoryName(location) + $@"\{nameof(I18n)}\Text_Incompatible.xml";
|
||||
var sut = new XmlTextResource(path);
|
||||
|
||||
var text = sut.LoadText();
|
||||
|
||||
Assert.IsNotNull(text);
|
||||
Assert.IsTrue(text.Count == 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(ArgumentException))]
|
||||
public void MustNotAcceptInvalidPath()
|
||||
{
|
||||
new XmlTextResource("This is not a valid path");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(ArgumentNullException))]
|
||||
public void MustNotAcceptNullAsPath()
|
||||
{
|
||||
new XmlTextResource(null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,12 +69,14 @@
|
|||
<HintPath>..\packages\Moq.4.7.63\lib\net45\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Behaviour\RuntimeControllerTests.cs" />
|
||||
<Compile Include="Behaviour\StartupControllerTests.cs" />
|
||||
<Compile Include="Behaviour\ShutdownControllerTests.cs" />
|
||||
<Compile Include="I18n\TextTests.cs" />
|
||||
<Compile Include="I18n\XmlTextResourceTests.cs" />
|
||||
<Compile Include="Logging\LoggerTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
@ -91,6 +93,17 @@
|
|||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="I18n\Text_Invalid.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="I18n\Text_Incompatible.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="I18n\Text_Valid.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
|
49
SafeExamBrowser.Core/Behaviour/Operations/I18nOperation.cs
Normal file
49
SafeExamBrowser.Core/Behaviour/Operations/I18nOperation.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* 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.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Core.I18n;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour.Operations
|
||||
{
|
||||
public class I18nOperation : IOperation
|
||||
{
|
||||
private ILogger logger;
|
||||
private IText text;
|
||||
|
||||
public ISplashScreen SplashScreen { private get; set; }
|
||||
|
||||
public I18nOperation(ILogger logger, IText text)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info($"Loading default text data (the currently active culture is '{CultureInfo.CurrentCulture.Name}')...");
|
||||
|
||||
var location = Assembly.GetAssembly(typeof(XmlTextResource)).Location;
|
||||
var path = Path.GetDirectoryName(location) + $@"\{nameof(I18n)}\Text.xml";
|
||||
var textResource = new XmlTextResource(path);
|
||||
|
||||
text.Initialize(textResource);
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
// Nothing to do here...
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
|
||||
public void Stop()
|
||||
{
|
||||
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
||||
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
|
||||
windowMonitor.WindowChanged -= WindowMonitor_WindowChanged;
|
||||
}
|
||||
|
|
|
@ -9,26 +9,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Core.I18n
|
||||
{
|
||||
public class Text : IText
|
||||
{
|
||||
private readonly IDictionary<TextKey, string> cache;
|
||||
private IDictionary<TextKey, string> cache = new Dictionary<TextKey, string>();
|
||||
private ILogger logger;
|
||||
|
||||
public Text(ITextResource resource)
|
||||
public Text(ILogger logger)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(resource));
|
||||
}
|
||||
|
||||
cache = resource.LoadText() ?? new Dictionary<TextKey, string>();
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public string Get(TextKey key)
|
||||
{
|
||||
return cache.ContainsKey(key) ? cache[key] : $"Could not find string for key '{key}'!";
|
||||
}
|
||||
|
||||
public void Initialize(ITextResource resource)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(resource));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
cache = resource.LoadText() ?? new Dictionary<TextKey, string>();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to load text data from provided resource!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
|
||||
|
@ -17,10 +16,30 @@ namespace SafeExamBrowser.Core.I18n
|
|||
{
|
||||
public class XmlTextResource : ITextResource
|
||||
{
|
||||
private string path;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new text resource for an XML file located at the specified path.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ArgumentException">If the specifed file does not exist.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">If the given path is null.</exception>
|
||||
public XmlTextResource(string path)
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new ArgumentException("The specified file does not exist!");
|
||||
}
|
||||
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public IDictionary<TextKey, string> LoadText()
|
||||
{
|
||||
var assembly = Assembly.GetAssembly(typeof(XmlTextResource)).Location;
|
||||
var path = Path.GetDirectoryName(assembly) + $@"\{nameof(I18n)}\Text.xml";
|
||||
var xml = XDocument.Load(path);
|
||||
var text = new Dictionary<TextKey, string>();
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Behaviour\Operations\ClipboardOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\I18nOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\KeyboardInterceptorOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\MouseInterceptorOperation.cs" />
|
||||
<Compile Include="Behaviour\RuntimeController.cs" />
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace SafeExamBrowser.UserInterface.Classic
|
|||
|
||||
private void InitializeSplashScreen()
|
||||
{
|
||||
InfoTextBlock.Inlines.Add(new Run($"{text.Get(TextKey.Version)} {settings.ProgramVersion}") { FontStyle = FontStyles.Italic });
|
||||
InfoTextBlock.Inlines.Add(new Run($"Version {settings.ProgramVersion}") { FontStyle = FontStyles.Italic });
|
||||
InfoTextBlock.Inlines.Add(new LineBreak());
|
||||
InfoTextBlock.Inlines.Add(new LineBreak());
|
||||
InfoTextBlock.Inlines.Add(new Run(settings.ProgramCopyright) { FontSize = 10 });
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace SafeExamBrowser.UserInterface.Windows10
|
|||
|
||||
private void InitializeSplashScreen()
|
||||
{
|
||||
InfoTextBlock.Inlines.Add(new Run($"{text.Get(TextKey.Version)} {settings.ProgramVersion}") { FontStyle = FontStyles.Italic });
|
||||
InfoTextBlock.Inlines.Add(new Run($"Version {settings.ProgramVersion}") { FontStyle = FontStyles.Italic });
|
||||
InfoTextBlock.Inlines.Add(new LineBreak());
|
||||
InfoTextBlock.Inlines.Add(new LineBreak());
|
||||
InfoTextBlock.Inlines.Add(new Run(settings.ProgramCopyright) { FontSize = 10 });
|
||||
|
|
|
@ -51,7 +51,6 @@ namespace SafeExamBrowser
|
|||
private ISystemComponent<ISystemPowerSupplyControl> powerSupply;
|
||||
private ISystemInfo systemInfo;
|
||||
private IText text;
|
||||
private ITextResource textResource;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
private IWindowMonitor windowMonitor;
|
||||
|
||||
|
@ -68,12 +67,11 @@ namespace SafeExamBrowser
|
|||
nativeMethods = new NativeMethods();
|
||||
settings = new Settings();
|
||||
systemInfo = new SystemInfo();
|
||||
textResource = new XmlTextResource();
|
||||
uiFactory = new UserInterfaceFactory();
|
||||
|
||||
logger.Subscribe(new LogFileWriter(logFormatter, settings));
|
||||
|
||||
text = new Text(textResource);
|
||||
text = new Text(logger);
|
||||
Taskbar = new Taskbar(new ModuleLogger(logger, typeof(Taskbar)));
|
||||
browserController = new BrowserApplicationController(settings, text, uiFactory);
|
||||
displayMonitor = new DisplayMonitor(new ModuleLogger(logger, typeof(DisplayMonitor)), nativeMethods);
|
||||
|
@ -89,6 +87,7 @@ namespace SafeExamBrowser
|
|||
StartupController = new StartupController(logger, settings, systemInfo, text, uiFactory);
|
||||
|
||||
StartupOperations = new Queue<IOperation>();
|
||||
StartupOperations.Enqueue(new I18nOperation(logger, text));
|
||||
StartupOperations.Enqueue(new KeyboardInterceptorOperation(keyboardInterceptor, logger, nativeMethods));
|
||||
StartupOperations.Enqueue(new WindowMonitorOperation(logger, windowMonitor));
|
||||
StartupOperations.Enqueue(new ProcessMonitorOperation(logger, processMonitor));
|
||||
|
|
Loading…
Reference in a new issue