Skip to content

Commit 79408cf

Browse files
committed
Add unit test project and test coverage
Introduced CodeContext.Tests project with xUnit-based tests for core services and utilities, including FileFilterService, GitHelper, Guard, PathResolver, and StatsCalculator. Updated solution and main project to exclude test files from compilation and resources.
1 parent 66ca6bb commit 79408cf

8 files changed

Lines changed: 972 additions & 0 deletions
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<IsPackable>false</IsPackable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="coverlet.collector" Version="6.0.4" />
12+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
13+
<PackageReference Include="xunit" Version="2.9.3" />
14+
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<Using Include="Xunit" />
19+
</ItemGroup>
20+
21+
<ItemGroup>
22+
<ProjectReference Include="..\CodeContext.csproj" />
23+
</ItemGroup>
24+
25+
</Project>
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
using CodeContext.Configuration;
2+
using CodeContext.Services;
3+
using Xunit;
4+
5+
namespace CodeContext.Tests;
6+
7+
/// <summary>
8+
/// Tests for the FileFilterService class that handles file and directory filtering.
9+
/// </summary>
10+
public class FileFilterServiceTests : IDisposable
11+
{
12+
private readonly FilterConfiguration _config;
13+
private readonly FileFilterService _service;
14+
private readonly string _tempRoot;
15+
16+
public FileFilterServiceTests()
17+
{
18+
_config = new FilterConfiguration();
19+
_service = new FileFilterService(_config);
20+
_tempRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
21+
Directory.CreateDirectory(_tempRoot);
22+
}
23+
24+
[Fact]
25+
public void ShouldSkip_WithNullFileSystemInfo_ThrowsArgumentNullException()
26+
{
27+
// Act & Assert
28+
Assert.Throws<ArgumentNullException>(() =>
29+
_service.ShouldSkip(null!, _tempRoot));
30+
}
31+
32+
[Fact]
33+
public void ShouldSkip_WithNullRootPath_ThrowsArgumentException()
34+
{
35+
// Arrange
36+
var tempFile = Path.Combine(_tempRoot, "test.txt");
37+
File.WriteAllText(tempFile, "test");
38+
var fileInfo = new FileInfo(tempFile);
39+
40+
try
41+
{
42+
// Act & Assert
43+
Assert.Throws<ArgumentException>(() =>
44+
_service.ShouldSkip(fileInfo, null!));
45+
}
46+
finally
47+
{
48+
File.Delete(tempFile);
49+
}
50+
}
51+
52+
[Fact]
53+
public void ShouldSkip_WithIgnoredExtension_ReturnsTrue()
54+
{
55+
// Arrange
56+
var tempFile = Path.Combine(_tempRoot, "test.exe");
57+
File.WriteAllText(tempFile, "test");
58+
var fileInfo = new FileInfo(tempFile);
59+
60+
try
61+
{
62+
// Act
63+
var result = _service.ShouldSkip(fileInfo, _tempRoot);
64+
65+
// Assert
66+
Assert.True(result);
67+
}
68+
finally
69+
{
70+
File.Delete(tempFile);
71+
}
72+
}
73+
74+
[Fact]
75+
public void ShouldSkip_WithAllowedExtension_ReturnsFalse()
76+
{
77+
// Arrange
78+
var tempFile = Path.Combine(_tempRoot, "test.cs");
79+
File.WriteAllText(tempFile, "// C# code");
80+
var fileInfo = new FileInfo(tempFile);
81+
82+
try
83+
{
84+
// Act
85+
var result = _service.ShouldSkip(fileInfo, _tempRoot);
86+
87+
// Assert
88+
Assert.False(result);
89+
}
90+
finally
91+
{
92+
File.Delete(tempFile);
93+
}
94+
}
95+
96+
[Fact]
97+
public void ShouldSkip_WithIgnoredFileName_ReturnsTrue()
98+
{
99+
// Arrange
100+
var tempFile = Path.Combine(_tempRoot, ".gitignore");
101+
File.WriteAllText(tempFile, "test");
102+
var fileInfo = new FileInfo(tempFile);
103+
104+
try
105+
{
106+
// Act
107+
var result = _service.ShouldSkip(fileInfo, _tempRoot);
108+
109+
// Assert
110+
Assert.True(result);
111+
}
112+
finally
113+
{
114+
File.Delete(tempFile);
115+
}
116+
}
117+
118+
[Fact]
119+
public void ShouldSkip_WithIgnoredDirectory_ReturnsTrue()
120+
{
121+
// Arrange
122+
var ignoredDir = Path.Combine(_tempRoot, "node_modules");
123+
Directory.CreateDirectory(ignoredDir);
124+
var fileInIgnoredDir = Path.Combine(ignoredDir, "package.js");
125+
File.WriteAllText(fileInIgnoredDir, "test");
126+
var fileInfo = new FileInfo(fileInIgnoredDir);
127+
128+
try
129+
{
130+
// Act
131+
var result = _service.ShouldSkip(fileInfo, _tempRoot);
132+
133+
// Assert
134+
Assert.True(result);
135+
}
136+
finally
137+
{
138+
Directory.Delete(ignoredDir, true);
139+
}
140+
}
141+
142+
[Fact]
143+
public void ShouldSkip_WithFileTooLarge_ReturnsTrue()
144+
{
145+
// Arrange
146+
var tempFile = Path.Combine(_tempRoot, "large.txt");
147+
var largeContent = new string('x', (int)_config.MaxFileSizeBytes + 1);
148+
File.WriteAllText(tempFile, largeContent);
149+
var fileInfo = new FileInfo(tempFile);
150+
151+
try
152+
{
153+
// Act
154+
var result = _service.ShouldSkip(fileInfo, _tempRoot);
155+
156+
// Assert
157+
Assert.True(result);
158+
}
159+
finally
160+
{
161+
File.Delete(tempFile);
162+
}
163+
}
164+
165+
[Fact]
166+
public void ShouldSkip_WithCompoundExtension_ReturnsTrue()
167+
{
168+
// Arrange
169+
var tempFile = Path.Combine(_tempRoot, "app.min.js");
170+
File.WriteAllText(tempFile, "minified js");
171+
var fileInfo = new FileInfo(tempFile);
172+
173+
try
174+
{
175+
// Act
176+
var result = _service.ShouldSkip(fileInfo, _tempRoot);
177+
178+
// Assert
179+
Assert.True(result);
180+
}
181+
finally
182+
{
183+
File.Delete(tempFile);
184+
}
185+
}
186+
187+
[Fact]
188+
public void ShouldSkip_WithGeneratedCodeMarker_ReturnsTrue()
189+
{
190+
// Arrange
191+
var tempFile = Path.Combine(_tempRoot, "Generated.cs");
192+
File.WriteAllText(tempFile, "// <auto-generated />\nnamespace Test { }");
193+
var fileInfo = new FileInfo(tempFile);
194+
195+
try
196+
{
197+
// Act
198+
var result = _service.ShouldSkip(fileInfo, _tempRoot);
199+
200+
// Assert
201+
Assert.True(result);
202+
}
203+
finally
204+
{
205+
File.Delete(tempFile);
206+
}
207+
}
208+
209+
[Fact]
210+
public void ShouldSkip_WithDirectory_ChecksForIgnoredDirectoryNames()
211+
{
212+
// Arrange
213+
var ignoredDir = Path.Combine(_tempRoot, "bin");
214+
Directory.CreateDirectory(ignoredDir);
215+
var dirInfo = new DirectoryInfo(ignoredDir);
216+
217+
try
218+
{
219+
// Act
220+
var result = _service.ShouldSkip(dirInfo, _tempRoot);
221+
222+
// Assert
223+
Assert.True(result);
224+
}
225+
finally
226+
{
227+
Directory.Delete(ignoredDir);
228+
}
229+
}
230+
231+
[Fact]
232+
public void ShouldSkip_WithNormalDirectory_ReturnsFalse()
233+
{
234+
// Arrange
235+
var normalDir = Path.Combine(_tempRoot, "src");
236+
Directory.CreateDirectory(normalDir);
237+
var dirInfo = new DirectoryInfo(normalDir);
238+
239+
try
240+
{
241+
// Act
242+
var result = _service.ShouldSkip(dirInfo, _tempRoot);
243+
244+
// Assert
245+
Assert.False(result);
246+
}
247+
finally
248+
{
249+
Directory.Delete(normalDir);
250+
}
251+
}
252+
253+
public void Dispose()
254+
{
255+
try
256+
{
257+
if (Directory.Exists(_tempRoot))
258+
{
259+
Directory.Delete(_tempRoot, true);
260+
}
261+
}
262+
catch
263+
{
264+
// Best effort cleanup
265+
}
266+
}
267+
}

0 commit comments

Comments
 (0)