Skip to content

Commit 39031ff

Browse files
author
mpacon
authored
Merge pull request #44 from conplementAG/2.1.0
More logging, more robust io handling, fallback to reference options,…
2 parents 99956ae + 33258d8 commit 39031ff

11 files changed

Lines changed: 816 additions & 131 deletions

Calinga.NET.Tests/Calinga.NET.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<PackageReference Include="Moq" Version="4.16.1" />
1313
<PackageReference Include="MSTest.TestAdapter" Version="2.2.7" />
1414
<PackageReference Include="MSTest.TestFramework" Version="2.2.7" />
15-
<PackageReference Include="coverlet.collector" Version="3.1.0">
15+
<PackageReference Include="coverlet.collector" Version="6.0.4">
1616
<PrivateAssets>all</PrivateAssets>
1717
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1818
</PackageReference>

Calinga.NET.Tests/CalingaServiceTests.cs

Lines changed: 242 additions & 44 deletions
Large diffs are not rendered by default.
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.VisualStudio.TestTools.UnitTesting;
6+
using Calinga.NET.Caching;
7+
using Calinga.NET.Infrastructure;
8+
using Calinga.NET.Infrastructure.Exceptions;
9+
using Moq;
10+
using Newtonsoft.Json;
11+
12+
namespace Calinga.NET.Tests
13+
{
14+
[TestClass]
15+
public class FileCachingServiceTests
16+
{
17+
private Mock<ILogger> _logger;
18+
private Mock<IFileSystem> _fileSystem;
19+
private CalingaServiceSettings _settings;
20+
private FileCachingService _service;
21+
22+
[TestInitialize]
23+
public void Init()
24+
{
25+
_logger = new Mock<ILogger>();
26+
_fileSystem = new Mock<IFileSystem>();
27+
_settings = new CalingaServiceSettings
28+
{
29+
DoNotWriteCacheFiles = false,
30+
CacheDirectory = "test_cache",
31+
Organization = "org",
32+
Team = "team",
33+
Project = "project"
34+
};
35+
_service = new FileCachingService(_settings, _logger.Object, _fileSystem.Object);
36+
}
37+
38+
[TestMethod]
39+
public async Task StoreTranslationsAsync_CreatesFileWithValidJson()
40+
{
41+
// Arrange
42+
var translations = new Dictionary<string, string> { { "key1", "value1" } };
43+
var language = "en";
44+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.json");
45+
var tempFilePath = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.temp.json");
46+
_fileSystem.Setup(fs => fs.CreateDirectory(It.IsAny<string>()));
47+
_fileSystem.Setup(fs => fs.WriteAllTextAsync(tempFilePath, It.IsAny<string>())).Returns(Task.CompletedTask);
48+
_fileSystem.Setup(fs => fs.ReadAllTextAsync(tempFilePath)).ReturnsAsync(JsonConvert.SerializeObject(translations));
49+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(false);
50+
_fileSystem.Setup(fs => fs.ReplaceFile(tempFilePath, path, null));
51+
52+
// Act
53+
await _service.StoreTranslationsAsync(language, translations);
54+
55+
// Assert
56+
_fileSystem.Verify(fs => fs.CreateDirectory(It.IsAny<string>()), Times.Once);
57+
_fileSystem.Verify(fs => fs.WriteAllTextAsync(tempFilePath, It.IsAny<string>()), Times.Once);
58+
_fileSystem.Verify(fs => fs.ReplaceFile(tempFilePath, path, null), Times.Once);
59+
}
60+
61+
[TestMethod]
62+
public async Task StoreTranslationsAsync_DoesNotCreateFileWhenDoNotWriteCacheFilesIsTrue()
63+
{
64+
// Arrange
65+
_settings.DoNotWriteCacheFiles = true;
66+
var translations = new Dictionary<string, string> { { "key1", "value1" } };
67+
var language = "en";
68+
69+
// Act
70+
await _service.StoreTranslationsAsync(language, translations);
71+
72+
// Assert
73+
_fileSystem.Verify(fs => fs.CreateDirectory(It.IsAny<string>()), Times.Never);
74+
_fileSystem.Verify(fs => fs.WriteAllTextAsync(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
75+
}
76+
77+
[TestMethod]
78+
public async Task StoreTranslationsAsync_LogsWarningOnIOException()
79+
{
80+
// Arrange
81+
var translations = new Dictionary<string, string> { { "key1", "value1" } };
82+
var language = "en";
83+
var tempFilePath = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.temp.json");
84+
_fileSystem.Setup(fs => fs.CreateDirectory(It.IsAny<string>()));
85+
_fileSystem.Setup(fs => fs.WriteAllTextAsync(tempFilePath, It.IsAny<string>())).Throws<IOException>();
86+
87+
// Act
88+
await _service.StoreTranslationsAsync(language, translations);
89+
90+
// Assert
91+
_logger.Verify(l => l.Warn(It.IsAny<string>()), Times.Once);
92+
}
93+
94+
[TestMethod]
95+
public async Task StoreTranslationsAsync_OverwritesExistingFile()
96+
{
97+
// Arrange
98+
var translations = new Dictionary<string, string> { { "key1", "value1" } };
99+
var language = "en";
100+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.json");
101+
var tempFilePath = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.temp.json");
102+
var prevFilePath = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.prev.json");
103+
_fileSystem.Setup(fs => fs.CreateDirectory(It.IsAny<string>()));
104+
_fileSystem.Setup(fs => fs.WriteAllTextAsync(tempFilePath, It.IsAny<string>())).Returns(Task.CompletedTask);
105+
_fileSystem.Setup(fs => fs.ReadAllTextAsync(tempFilePath)).ReturnsAsync(JsonConvert.SerializeObject(translations));
106+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(true);
107+
_fileSystem.Setup(fs => fs.ReplaceFile(tempFilePath, path, null));
108+
109+
// Act
110+
await _service.StoreTranslationsAsync(language, translations);
111+
112+
// Assert
113+
_fileSystem.Verify(fs => fs.ReplaceFile(path, prevFilePath, null), Times.Once);
114+
_fileSystem.Verify(fs => fs.ReplaceFile(tempFilePath, path, null), Times.Once);
115+
}
116+
117+
118+
[TestMethod]
119+
public async Task StoreTranslationsAsync_HandlesEmptyTranslations()
120+
{
121+
// Arrange
122+
var translations = new Dictionary<string, string>();
123+
var language = "en";
124+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.json");
125+
var tempFilePath = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.temp.json");
126+
_fileSystem.Setup(fs => fs.CreateDirectory(It.IsAny<string>()));
127+
_fileSystem.Setup(fs => fs.WriteAllTextAsync(tempFilePath, It.IsAny<string>())).Returns(Task.CompletedTask);
128+
_fileSystem.Setup(fs => fs.ReadAllTextAsync(tempFilePath)).ReturnsAsync(JsonConvert.SerializeObject(translations));
129+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(false);
130+
_fileSystem.Setup(fs => fs.ReplaceFile(tempFilePath, path, null));
131+
132+
// Act
133+
await _service.StoreTranslationsAsync(language, translations);
134+
135+
// Assert
136+
_fileSystem.Verify(fs => fs.CreateDirectory(It.IsAny<string>()), Times.Once);
137+
_fileSystem.Verify(fs => fs.WriteAllTextAsync(tempFilePath, It.IsAny<string>()), Times.Once);
138+
_fileSystem.Verify(fs => fs.ReplaceFile(tempFilePath, path, null), Times.Once);
139+
}
140+
141+
[TestMethod]
142+
public async Task GetTranslations_FileDoesNotExist_ReturnsEmptyCacheResponse()
143+
{
144+
// Arrange
145+
var language = "en";
146+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.json");
147+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(false);
148+
149+
// Act
150+
var result = await _service.GetTranslations(language, false);
151+
152+
// Assert
153+
Assert.IsFalse(result.FoundInCache);
154+
Assert.AreEqual(0, result.Result.Count);
155+
}
156+
157+
[TestMethod]
158+
public async Task GetTranslations_FileExists_ReturnsValidTranslations()
159+
{
160+
// Arrange
161+
var language = "en";
162+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.json");
163+
var translations = new Dictionary<string, string> { { "key1", "value1" } };
164+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(true);
165+
_fileSystem.Setup(fs => fs.ReadAllTextAsync(path)).ReturnsAsync(JsonConvert.SerializeObject(translations));
166+
167+
// Act
168+
var result = await _service.GetTranslations(language, false);
169+
170+
// Assert
171+
Assert.IsTrue(result.FoundInCache);
172+
CollectionAssert.AreEquivalent(translations.ToList(), result.Result.ToList());
173+
}
174+
175+
[TestMethod]
176+
public async Task GetTranslations_FileExists_ThrowsIOException()
177+
{
178+
// Arrange
179+
var language = "en";
180+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "EN.json");
181+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(true);
182+
_fileSystem.Setup(fs => fs.ReadAllTextAsync(path)).Throws<IOException>();
183+
184+
// Act & Assert
185+
await Assert.ThrowsExceptionAsync<TranslationsNotAvailableException>(() => _service.GetTranslations(language, false));
186+
}
187+
188+
[TestMethod]
189+
public async Task GetLanguages_FileDoesNotExist_ReturnsEmptyCachedLanguageListResponse()
190+
{
191+
// Arrange
192+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "Languages.json");
193+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(false);
194+
195+
// Act
196+
var result = await _service.GetLanguages();
197+
198+
// Assert
199+
Assert.IsFalse(result.FoundInCache);
200+
Assert.AreEqual(0, result.Result.Count);
201+
}
202+
203+
[TestMethod]
204+
public async Task GetLanguages_FileExists_ReturnsValidLanguages()
205+
{
206+
// Arrange
207+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "Languages.json");
208+
var languages = new List<Language> { new Language { Name = "en" } };
209+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(true);
210+
_fileSystem.Setup(fs => fs.ReadAllTextAsync(path)).ReturnsAsync(JsonConvert.SerializeObject(languages));
211+
212+
// Act
213+
var result = await _service.GetLanguages();
214+
215+
// Assert
216+
Assert.IsTrue(result.FoundInCache);
217+
Assert.AreEqual(1, result.Result.Count);
218+
Assert.AreEqual("en", result.Result[0].Name);
219+
Assert.IsFalse(result.Result[0].IsReference);
220+
}
221+
222+
[TestMethod]
223+
public async Task GetLanguages_FileExists_ThrowsIOException()
224+
{
225+
// Arrange
226+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "Languages.json");
227+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(true);
228+
_fileSystem.Setup(fs => fs.ReadAllTextAsync(path)).Throws<IOException>();
229+
230+
// Act & Assert
231+
await Assert.ThrowsExceptionAsync<TranslationsNotAvailableException>(() => _service.GetLanguages());
232+
}
233+
234+
[TestMethod]
235+
public async Task ClearCache_DoNotWriteCacheFilesIsTrue_DoesNothing()
236+
{
237+
// Arrange
238+
_settings.DoNotWriteCacheFiles = true;
239+
240+
// Act
241+
await _service.ClearCache();
242+
243+
// Assert
244+
_fileSystem.Verify(fs => fs.DeleteDirectory(It.IsAny<string>()), Times.Never);
245+
}
246+
247+
[TestMethod]
248+
public async Task StoreLanguagesAsync_DoNotWriteCacheFilesIsTrue_DoesNothing()
249+
{
250+
// Arrange
251+
_settings.DoNotWriteCacheFiles = true;
252+
var languages = new List<Language> { new Language { Name = "en" } };
253+
254+
// Act
255+
await _service.StoreLanguagesAsync(languages);
256+
257+
// Assert
258+
_fileSystem.Verify(fs => fs.CreateDirectory(It.IsAny<string>()), Times.Never);
259+
_fileSystem.Verify(fs => fs.WriteAllTextAsync(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
260+
}
261+
262+
[TestMethod]
263+
public async Task StoreLanguagesAsync_CreatesFileWithValidJson()
264+
{
265+
// Arrange
266+
var languages = new List<Language> { new Language { Name = "en" } };
267+
var path = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project, "Languages.json");
268+
var tempFilePath = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project,
269+
"Languages.temp.json");
270+
_fileSystem.Setup(fs => fs.CreateDirectory(It.IsAny<string>()));
271+
_fileSystem.Setup(fs => fs.WriteAllTextAsync(tempFilePath, It.IsAny<string>())).Returns(Task.CompletedTask);
272+
_fileSystem.Setup(fs => fs.ReadAllTextAsync(tempFilePath)).ReturnsAsync(JsonConvert.SerializeObject(languages));
273+
_fileSystem.Setup(fs => fs.FileExists(path)).Returns(false);
274+
_fileSystem.Setup(fs => fs.ReplaceFile(tempFilePath, path, null));
275+
276+
// Act
277+
await _service.StoreLanguagesAsync(languages);
278+
279+
// Assert
280+
_fileSystem.Verify(fs => fs.CreateDirectory(It.IsAny<string>()), Times.Once);
281+
_fileSystem.Verify(fs => fs.WriteAllTextAsync(tempFilePath, It.IsAny<string>()), Times.Once);
282+
_fileSystem.Verify(fs => fs.ReplaceFile(tempFilePath, path, null), Times.Once);
283+
}
284+
285+
[TestMethod]
286+
public async Task StoreLanguagesAsync_ThrowsIOException()
287+
{
288+
// Arrange
289+
var languages = new List<Language> { new Language { Name = "en" } };
290+
var tempFilePath = Path.Combine(_settings.CacheDirectory, _settings.Organization, _settings.Team, _settings.Project,
291+
"Languages.temp.json");
292+
_fileSystem.Setup(fs => fs.CreateDirectory(It.IsAny<string>()));
293+
_fileSystem.Setup(fs => fs.WriteAllTextAsync(tempFilePath, It.IsAny<string>())).Throws<IOException>();
294+
295+
// Act
296+
await _service.StoreLanguagesAsync(languages);
297+
298+
// Assert
299+
_logger.Verify(l => l.Warn(It.IsAny<string>()), Times.Once);
300+
}
301+
302+
303+
}
304+
}

0 commit comments

Comments
 (0)