Skip to content

Commit 4c3a8cd

Browse files
committed
Added database service tests and updated ordering logic to match eventing library
1 parent 248ee43 commit 4c3a8cd

3 files changed

Lines changed: 391 additions & 10 deletions

File tree

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
// // Copyright (c) Microsoft Corporation.
2+
// // Licensed under the MIT License.
3+
4+
using EventLogExpert.UI.Interfaces;
5+
using EventLogExpert.UI.Services;
6+
using NSubstitute;
7+
8+
namespace EventLogExpert.UI.Tests.Services;
9+
10+
public sealed class DatabaseServiceTests
11+
{
12+
[Fact]
13+
public void DisabledDatabases_AfterUpdate_ShouldReturnUpdatedValues()
14+
{
15+
// Arrange
16+
var mockPreferencesProvider = Substitute.For<IPreferencesProvider>();
17+
mockPreferencesProvider.DisabledDatabasesPreference.Returns(["InitialDisabled"]);
18+
19+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
20+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases().Returns([]);
21+
22+
var databaseService = CreateDatabaseService(
23+
mockEnabledDatabaseCollectionProvider,
24+
mockPreferencesProvider);
25+
26+
// Act
27+
databaseService.UpdateDisabledDatabases(["NewDisabled1", "NewDisabled2"]);
28+
var result = databaseService.DisabledDatabases.ToList();
29+
30+
// Assert
31+
Assert.Equal(2, result.Count);
32+
Assert.Contains("NewDisabled1", result);
33+
Assert.Contains("NewDisabled2", result);
34+
}
35+
36+
[Fact]
37+
public void DisabledDatabases_WhenAccessed_ShouldReturnFromPreferences()
38+
{
39+
// Arrange
40+
var mockPreferencesProvider = Substitute.For<IPreferencesProvider>();
41+
mockPreferencesProvider.DisabledDatabasesPreference.Returns(["DisabledDb1", "DisabledDb2"]);
42+
43+
var databaseService = CreateDatabaseService(preferencesProvider: mockPreferencesProvider);
44+
45+
// Act
46+
var result = databaseService.DisabledDatabases.ToList();
47+
48+
// Assert
49+
Assert.Equal(2, result.Count);
50+
Assert.Contains("DisabledDb1", result);
51+
Assert.Contains("DisabledDb2", result);
52+
}
53+
54+
[Fact]
55+
public void DisabledDatabases_WhenAccessedMultipleTimes_ShouldCacheResult()
56+
{
57+
// Arrange
58+
var mockPreferencesProvider = Substitute.For<IPreferencesProvider>();
59+
mockPreferencesProvider.DisabledDatabasesPreference.Returns(["DisabledDb"]);
60+
61+
var databaseService = CreateDatabaseService(preferencesProvider: mockPreferencesProvider);
62+
63+
// Act
64+
_ = databaseService.DisabledDatabases;
65+
_ = databaseService.DisabledDatabases;
66+
_ = databaseService.DisabledDatabases;
67+
68+
// Assert
69+
_ = mockPreferencesProvider.Received(1).DisabledDatabasesPreference;
70+
}
71+
72+
[Fact]
73+
public void LoadDatabases_WhenCalled_ShouldInvokeLoadedDatabasesChanged()
74+
{
75+
// Arrange
76+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
77+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases().Returns(["Database A"]);
78+
79+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
80+
81+
IEnumerable<string>? receivedDatabases = null;
82+
object? receivedSender = null;
83+
84+
databaseService.LoadedDatabasesChanged += (sender, databases) =>
85+
{
86+
receivedSender = sender;
87+
receivedDatabases = databases;
88+
};
89+
90+
// Act
91+
databaseService.LoadDatabases();
92+
93+
// Assert
94+
Assert.NotNull(receivedDatabases);
95+
Assert.Same(databaseService, receivedSender);
96+
Assert.Contains("Database A", receivedDatabases);
97+
}
98+
99+
[Fact]
100+
public void LoadDatabases_WhenCalled_ShouldRefreshLoadedDatabases()
101+
{
102+
// Arrange
103+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
104+
105+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases()
106+
.Returns(["Database A"], ["Database B", "Database C"]);
107+
108+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
109+
110+
// Act
111+
var initialResult = databaseService.LoadedDatabases.ToList();
112+
databaseService.LoadDatabases();
113+
var refreshedResult = databaseService.LoadedDatabases.ToList();
114+
115+
// Assert
116+
Assert.Single(initialResult);
117+
Assert.Equal("Database A", initialResult[0]);
118+
Assert.Equal(2, refreshedResult.Count);
119+
Assert.Contains("Database B", refreshedResult);
120+
Assert.Contains("Database C", refreshedResult);
121+
}
122+
123+
[Fact]
124+
public void LoadDatabases_WhenNoEventHandler_ShouldNotThrow()
125+
{
126+
// Arrange
127+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
128+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases().Returns(["Database A"]);
129+
130+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
131+
132+
// Act & Assert
133+
var exception = Record.Exception(() => databaseService.LoadDatabases());
134+
Assert.Null(exception);
135+
}
136+
137+
[Fact]
138+
public void LoadedDatabases_WhenAccessed_ShouldReturnSortedDatabases()
139+
{
140+
// Arrange
141+
// Names with pattern "Name Version" sort by name asc, then version desc
142+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
143+
144+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases()
145+
.Returns(["Database C", "Database A", "Database B"]);
146+
147+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
148+
149+
// Act
150+
var result = databaseService.LoadedDatabases.ToList();
151+
152+
// Assert
153+
// "Database X" splits to FirstPart="Database " + SecondPart="X"
154+
// Sorted by FirstPart asc, then SecondPart desc: C, B, A
155+
Assert.Equal(3, result.Count);
156+
Assert.Equal("Database C", result[0]);
157+
Assert.Equal("Database B", result[1]);
158+
Assert.Equal("Database A", result[2]);
159+
}
160+
161+
[Fact]
162+
public void LoadedDatabases_WhenAccessedMultipleTimes_ShouldCacheResult()
163+
{
164+
// Arrange
165+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
166+
167+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases()
168+
.Returns(["Database A"]);
169+
170+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
171+
172+
// Act
173+
_ = databaseService.LoadedDatabases;
174+
_ = databaseService.LoadedDatabases;
175+
_ = databaseService.LoadedDatabases;
176+
177+
// Assert
178+
mockEnabledDatabaseCollectionProvider.Received(1).GetEnabledDatabases();
179+
}
180+
181+
[Fact]
182+
public void LoadedDatabases_WhenEmpty_ShouldReturnEmptyCollection()
183+
{
184+
// Arrange
185+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
186+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases().Returns([]);
187+
188+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
189+
190+
// Act
191+
var result = databaseService.LoadedDatabases;
192+
193+
// Assert
194+
Assert.Empty(result);
195+
}
196+
197+
[Fact]
198+
public void LoadedDatabases_WhenVersionedDatabases_ShouldSortByNameThenVersionDescending()
199+
{
200+
// Arrange
201+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
202+
203+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases()
204+
.Returns(["Windows 10", "Windows 11", "Windows 9", "Linux 1"]);
205+
206+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
207+
208+
// Act
209+
var result = databaseService.LoadedDatabases.ToList();
210+
211+
// Assert - Numeric sorting: 11 > 10 > 9, 1
212+
Assert.Equal(4, result.Count);
213+
Assert.Equal("Linux 1", result[0]);
214+
Assert.Equal("Windows 11", result[1]);
215+
Assert.Equal("Windows 10", result[2]);
216+
Assert.Equal("Windows 9", result[3]);
217+
}
218+
219+
[Fact]
220+
public void LoadedDatabases_WhenNumericVersions_ShouldSortNumericallyNotLexicographically()
221+
{
222+
// Arrange
223+
// This test ensures "10" sorts after "2" (numeric) rather than before it (lexicographic)
224+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
225+
226+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases()
227+
.Returns(["Server 2", "Server 10", "Server 1", "Server 20"]);
228+
229+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
230+
231+
// Act
232+
var result = databaseService.LoadedDatabases.ToList();
233+
234+
// Assert - Numeric descending: 20, 10, 2, 1
235+
Assert.Equal(4, result.Count);
236+
Assert.Equal("Server 20", result[0]);
237+
Assert.Equal("Server 10", result[1]);
238+
Assert.Equal("Server 2", result[2]);
239+
Assert.Equal("Server 1", result[3]);
240+
}
241+
242+
[Fact]
243+
public void LoadedDatabasesChanged_WhenSetToNull_ShouldNotThrowOnLoadDatabases()
244+
{
245+
// Arrange
246+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
247+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases().Returns(["Database A"]);
248+
249+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
250+
databaseService.LoadedDatabasesChanged = null;
251+
252+
// Act & Assert
253+
var exception = Record.Exception(() => databaseService.LoadDatabases());
254+
Assert.Null(exception);
255+
}
256+
257+
[Fact]
258+
public void SortDatabases_WhenMixedVersionedAndNonVersioned_ShouldSortCorrectly()
259+
{
260+
// Arrange
261+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
262+
263+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases()
264+
.Returns(["Windows 10", "SimpleDatabase", "Windows 11", "AnotherDb"]);
265+
266+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
267+
268+
// Act
269+
var result = databaseService.LoadedDatabases.ToList();
270+
271+
// Assert - Non-versioned first (no space pattern), then versioned with numeric sort
272+
Assert.Equal(4, result.Count);
273+
Assert.Equal("AnotherDb", result[0]);
274+
Assert.Equal("SimpleDatabase", result[1]);
275+
Assert.Equal("Windows 11", result[2]);
276+
Assert.Equal("Windows 10", result[3]);
277+
}
278+
279+
[Fact]
280+
public void UpdateDisabledDatabases_WhenCalled_ShouldInvokeLoadedDatabasesChanged()
281+
{
282+
// Arrange
283+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
284+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases().Returns(["Database A"]);
285+
286+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
287+
288+
var eventInvoked = false;
289+
databaseService.LoadedDatabasesChanged += (_, _) => eventInvoked = true;
290+
291+
// Act
292+
databaseService.UpdateDisabledDatabases(["DisabledDb"]);
293+
294+
// Assert
295+
Assert.True(eventInvoked);
296+
}
297+
298+
[Fact]
299+
public void UpdateDisabledDatabases_WhenCalled_ShouldReloadDatabases()
300+
{
301+
// Arrange
302+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
303+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases().Returns(["Database A"]);
304+
305+
var databaseService = CreateDatabaseService(mockEnabledDatabaseCollectionProvider);
306+
307+
// Act
308+
databaseService.UpdateDisabledDatabases(["DisabledDb"]);
309+
310+
// Assert - GetEnabledDatabases should be called once for reload (LoadedDatabases not accessed before)
311+
mockEnabledDatabaseCollectionProvider.Received(1).GetEnabledDatabases();
312+
}
313+
314+
[Fact]
315+
public void UpdateDisabledDatabases_WhenCalled_ShouldUpdatePreferences()
316+
{
317+
// Arrange
318+
var mockPreferencesProvider = Substitute.For<IPreferencesProvider>();
319+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
320+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases().Returns([]);
321+
322+
var databaseService = CreateDatabaseService(
323+
mockEnabledDatabaseCollectionProvider,
324+
mockPreferencesProvider);
325+
326+
var newDisabledDatabases = new List<string> { "NewDisabled1", "NewDisabled2" };
327+
328+
// Act
329+
databaseService.UpdateDisabledDatabases(newDisabledDatabases);
330+
331+
// Assert
332+
mockPreferencesProvider.Received(1).DisabledDatabasesPreference =
333+
Arg.Is<IEnumerable<string>>(x => x.Contains("NewDisabled1") && x.Contains("NewDisabled2"));
334+
}
335+
336+
[Fact]
337+
public void UpdateDisabledDatabases_WhenCalledWithEmptyList_ShouldUpdatePreferences()
338+
{
339+
// Arrange
340+
var mockPreferencesProvider = Substitute.For<IPreferencesProvider>();
341+
var mockEnabledDatabaseCollectionProvider = Substitute.For<IEnabledDatabaseCollectionProvider>();
342+
mockEnabledDatabaseCollectionProvider.GetEnabledDatabases().Returns([]);
343+
344+
var databaseService = CreateDatabaseService(
345+
mockEnabledDatabaseCollectionProvider,
346+
mockPreferencesProvider);
347+
348+
// Act
349+
databaseService.UpdateDisabledDatabases([]);
350+
351+
// Assert
352+
mockPreferencesProvider.Received(1).DisabledDatabasesPreference =
353+
Arg.Is<IEnumerable<string>>(x => !x.Any());
354+
}
355+
356+
private static DatabaseService CreateDatabaseService(
357+
IEnabledDatabaseCollectionProvider? enabledDatabaseCollectionProvider = null,
358+
IPreferencesProvider? preferencesProvider = null)
359+
{
360+
return new DatabaseService(
361+
enabledDatabaseCollectionProvider ?? Substitute.For<IEnabledDatabaseCollectionProvider>(),
362+
preferencesProvider ?? Substitute.For<IPreferencesProvider>());
363+
}
364+
}

src/EventLogExpert.UI/Options/FileLocationOptions.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,9 @@
33

44
namespace EventLogExpert.UI.Options;
55

6-
public class FileLocationOptions
6+
public class FileLocationOptions(string basePath)
77
{
8-
private readonly string _basePath;
9-
10-
public FileLocationOptions(string basePath)
11-
{
12-
_basePath = basePath;
13-
}
8+
private readonly string _basePath = basePath;
149

1510
public string DatabasePath => Path.Join(_basePath, "Databases");
1611

0 commit comments

Comments
 (0)