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