Continued implementing the scaffolding:

- Added composition root
- Implemented XML resource for I18n
This commit is contained in:
Damian Büchel 2017-07-06 10:56:03 +02:00
parent 936f72c8bd
commit 0e9571fe10
12 changed files with 165 additions and 23 deletions

View file

@ -13,21 +13,34 @@ using SafeExamBrowser.Core.I18n;
namespace SafeExamBrowser.Core.UnitTests
{
[TestClass]
public class StringsTests
public class TextTests
{
[TestMethod]
public void MustNeverBeNull()
{
Assert.IsNotNull(Text.Instance);
}
[TestMethod]
public void MustNeverReturnNull()
{
var text = Strings.Get((Key) (-1));
var text = Text.Instance.Get((Key) (-1));
Assert.IsNotNull(text);
}
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void MustNotAllowBeingNull()
{
Text.Instance = null;
}
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void MustNotAllowNullResource()
{
Strings.Initialize(null);
new Text(null);
}
}
}

View file

@ -48,7 +48,7 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="I18n\StringsTests.cs" />
<Compile Include="I18n\TextTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View file

@ -11,8 +11,8 @@ using SafeExamBrowser.Core.I18n;
namespace SafeExamBrowser.Core.Contracts
{
public interface IStringResource
public interface ITextResource
{
IDictionary<Key, string> LoadStrings();
IDictionary<Key, string> LoadText();
}
}

View file

@ -10,6 +10,7 @@ namespace SafeExamBrowser.Core.I18n
{
public enum Key
{
MessageBox_FatalErrorTitle,
MessageBox_SingleInstance,
MessageBox_SingleInstanceTitle
}

View file

@ -0,0 +1,21 @@
/*
* 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.Collections.Generic;
using SafeExamBrowser.Core.Contracts;
namespace SafeExamBrowser.Core.I18n
{
class NullTextResource : ITextResource
{
public IDictionary<Key, string> LoadText()
{
return new Dictionary<Key, string>();
}
}
}

View file

@ -12,21 +12,42 @@ using SafeExamBrowser.Core.Contracts;
namespace SafeExamBrowser.Core.I18n
{
public static class Strings
public class Text
{
private static IDictionary<Key, string> cache = new Dictionary<Key, string>();
private static Text instance;
private static readonly object @lock = new object();
public static void Initialize(IStringResource resource)
private IDictionary<Key, string> cache = new Dictionary<Key, string>();
public Text(ITextResource resource)
{
if (resource == null)
{
throw new ArgumentNullException(nameof(resource));
}
cache = resource.LoadStrings();
cache = resource.LoadText();
}
public static string Get(Key key)
public static Text Instance
{
get
{
lock (@lock)
{
return instance ?? new Text(new NullTextResource());
}
}
set
{
lock (@lock)
{
instance = value ?? throw new ArgumentNullException(nameof(value));
}
}
}
public string Get(Key key)
{
return cache.ContainsKey(key) ? cache[key] : $"Could not find string for key '{key}'!";
}

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<Text>
<MessageBox_FatalErrorTitle>Fatal Error</MessageBox_FatalErrorTitle>
<MessageBox_SingleInstance>You can only run one instance of SEB at a time.</MessageBox_SingleInstance>
<MessageBox_SingleInstanceTitle>Startup Not Allowed</MessageBox_SingleInstanceTitle>
</Text>

View file

@ -0,0 +1,38 @@
/*
* 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.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml.Linq;
using SafeExamBrowser.Core.Contracts;
namespace SafeExamBrowser.Core.I18n
{
public class XmlTextResource : ITextResource
{
public IDictionary<Key, 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<Key, string>();
foreach (var definition in xml.Root.Descendants())
{
if (Enum.TryParse(definition.Name.LocalName, out Key key))
{
text[key] = definition.Value;
}
}
return text;
}
}
}

View file

@ -40,14 +40,18 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Contracts\IStringResource.cs" />
<Compile Include="Contracts\ITextResource.cs" />
<Compile Include="Contracts\ITaskbar.cs" />
<Compile Include="I18n\Key.cs" />
<Compile Include="I18n\Strings.cs" />
<Compile Include="I18n\NullTextResource.cs" />
<Compile Include="I18n\Text.cs" />
<Compile Include="I18n\XmlTextResource.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="I18n\Text.xml" />
<Content Include="I18n\Text.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -10,7 +10,6 @@ using System;
using System.Threading;
using System.Windows;
using SafeExamBrowser.Core.I18n;
using SafeExamBrowser.UserInterface;
namespace SafeExamBrowser
{
@ -21,22 +20,36 @@ namespace SafeExamBrowser
[STAThread]
public static void Main()
{
if (mutex.WaitOne(TimeSpan.Zero, true))
try
{
StartApplication();
var compositionRoot = new CompositionRoot();
compositionRoot.InitializeGlobalModules();
compositionRoot.BuildObjectGraph();
StartApplication(compositionRoot.Taskbar);
}
catch (Exception e)
{
MessageBox.Show(e.Message + "\n\n" + e.StackTrace, Text.Instance.Get(Key.MessageBox_FatalErrorTitle));
}
}
private static void StartApplication(Window taskbar)
{
if (NoInstanceRunning())
{
new App().Run(taskbar);
}
else
{
MessageBox.Show(Strings.Get(Key.MessageBox_SingleInstance), Strings.Get(Key.MessageBox_SingleInstanceTitle));
MessageBox.Show(Text.Instance.Get(Key.MessageBox_SingleInstance), Text.Instance.Get(Key.MessageBox_SingleInstanceTitle));
}
}
private static void StartApplication()
private static bool NoInstanceRunning()
{
var app = new App();
var taskbar = new Taskbar();
app.Run(taskbar);
return mutex.WaitOne(TimeSpan.Zero, true);
}
}
}

View file

@ -0,0 +1,29 @@
/*
* 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.Windows;
using SafeExamBrowser.Core.I18n;
using SafeExamBrowser.UserInterface;
namespace SafeExamBrowser
{
class CompositionRoot
{
public Window Taskbar { get; private set; }
public void InitializeGlobalModules()
{
Text.Instance = new Text(new XmlTextResource());
}
public void BuildObjectGraph()
{
Taskbar = new Taskbar();
}
}
}

View file

@ -51,6 +51,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="App.cs" />
<Compile Include="CompositionRoot.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>