Skip to content

Commit

Permalink
Added test to cover the requisites
Browse files Browse the repository at this point in the history
  • Loading branch information
xusterlg committed Jan 5, 2025
1 parent 0fe07b9 commit 9590ac6
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 134 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
dotnet sonarscanner begin \
/k:"autoguru-au_kv-push" \
/o:"autoguru-au" \
/k:"vanguille_kv-push-sonar" \
/o:"vanguille" \
/d:sonar.cs.opencover.reportsPaths="./TestResults/Coverage/coverage.opencover.xml" \
/d:sonar.inclusions="**/*.cs" \
/d:sonar.exclusions="**/bin/**,**/obj/**" \
Expand Down
19 changes: 19 additions & 0 deletions src/KeyValuePush.Redis.Tests/KeyValuePush.Redis.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageReference Include="StackExchange.Redis" Version="2.7.17" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<PackageReference Include="Moq" Version="4.20.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\KeyValuePush.Redis\AutoGuru.KeyValuePush.Redis.csproj" />
</ItemGroup>

</Project>
29 changes: 29 additions & 0 deletions src/KeyValuePush.Redis.Tests/RedisPusherTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Moq;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace AutoGuru.KeyValuePush.Redis.Tests
{
public class RedisPusherTests
{
private readonly Mock<IDatabase> _mockDatabase;
private readonly RedisPusher _pusher;

public RedisPusherTests()
{
_mockDatabase = new Mock<IDatabase>();
_pusher = new RedisPusher();

// Usamos reflexión para inyectar el mock en el campo privado
var field = typeof(RedisPusher).GetField("_db", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
field?.SetValue(_pusher, _mockDatabase.Object);
}


}
}
114 changes: 52 additions & 62 deletions src/KeyValuePush.Tests/DefaultDictionaryBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using AutoGuru.KeyValuePush;
using Xunit;

namespace AutoGuru.KeyValuePush.Tests
namespace KeyValuePush.Tests
{
public class DefaultDictionaryBuilderTests
{
Expand Down Expand Up @@ -55,61 +56,85 @@ public void TryAdd_ShouldThrowException_WhenKeyExistsWithDifferentValue()
}

[Fact]
public async Task BuildAsync_ShouldReturnDictionary_WhenFilesAreValid()
public async Task BuildAsync_ShouldThrowException_WhenFileAccessFailsAsync()
{
var path = "TestFiles";
var path = "RestrictedFiles";
Directory.CreateDirectory(path);
File.WriteAllText(Path.Combine(path, "file1.txt"), "Content1");
File.WriteAllText(Path.Combine(path, "file2.txt"), "Content2");
var filePath = Path.Combine(path, "file1.txt");
File.WriteAllText(filePath, "Content1");

var result = await _builder.BuildAsync(path, "*.txt", SearchOption.TopDirectoryOnly, false, CancellationToken.None);
// Bloquear el archivo para simular acceso denegado
using (var fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
{
var exception = await Assert.ThrowsAsync<IOException>(() =>
_builder.BuildAsync(path, "*.txt", SearchOption.TopDirectoryOnly, false, CancellationToken.None));

Assert.Equal(2, result.Count);
Assert.Equal("Content1", result["file1"]);
Assert.Equal("Content2", result["file2"]);
Assert.Contains("being used by another process", exception.Message);
}

Directory.Delete(path, true);
File.Delete(filePath);
Directory.Delete(path);
}


[Fact]
public async Task BuildAsync_ShouldThrowJsonException_WhenJsonFileIsInvalid()
public async Task BuildAsync_ShouldRespectCancellationTokenAsync()
{
var path = "TestFiles";
Directory.CreateDirectory(path);
File.WriteAllText(Path.Combine(path, "file1.json"), "Invalid JSON Content");
File.WriteAllText(Path.Combine(path, "file1.txt"), "Content1");

using var cts = new CancellationTokenSource();
cts.Cancel();

var exception = await Assert.ThrowsAsync<JsonException>(() => _builder.BuildAsync(path, "*.json", SearchOption.TopDirectoryOnly, true, CancellationToken.None));
await Assert.ThrowsAsync<OperationCanceledException>(() =>
_builder.BuildAsync(path, "*.txt", SearchOption.TopDirectoryOnly, false, cts.Token));

Assert.Contains("is an invalid start of a value", exception.Message);
Directory.Delete(path, true);
}

[Fact]
public async Task BuildAsync_ShouldHandleEmptyDirectory()
public async Task BuildAsync_ShouldHandleDuplicateKeysInJsonFiles()
{
var path = "EmptyDirectory";
var path = "TestFiles";
Directory.CreateDirectory(path);

var result = await _builder.BuildAsync(path, "*.*", SearchOption.TopDirectoryOnly, false, CancellationToken.None);
// Crear un archivo JSON con claves únicas
var jsonContent = JsonSerializer.Serialize(new Dictionary<string, string>
{
{ "Key1", "Value1" },
{ "Key2", "Value2" }
});
File.WriteAllText(Path.Combine(path, "file1.json"), jsonContent);

var result = await _builder.BuildAsync(path, "*.json", SearchOption.TopDirectoryOnly, true, CancellationToken.None);

Assert.Equal(2, result.Count);
Assert.Equal("Value1", result["Key1"]);
Assert.Equal("Value2", result["Key2"]);

Assert.Empty(result);
Directory.Delete(path, true);
}


[Fact]
public async Task BuildAsync_ShouldReturnEmptyDictionary_WhenNoMatchingFilesFound()
public async Task BuildAsync_ShouldIgnoreFilesWithNonJsonExtensions()
{
var path = "TestFiles";
Directory.CreateDirectory(path);

var result = await _builder.BuildAsync(path, "*.xml", SearchOption.TopDirectoryOnly, false, CancellationToken.None);
// Crear un archivo con extensión no soportada
File.WriteAllText(Path.Combine(path, "file1.unsupported"), "Unsupported Content");

var result = await _builder.BuildAsync(path, "*.json", SearchOption.TopDirectoryOnly, false, CancellationToken.None);

Assert.Empty(result);
Directory.Delete(path, true);
}


[Fact]
public async Task BuildAsync_ShouldSkipJsonFiles_WhenRecurseIntoJsonFilesIsFalse()
public async Task BuildAsync_ShouldCombineJsonAndTextFiles()
{
var path = "TestFiles";
Directory.CreateDirectory(path);
Expand All @@ -119,50 +144,15 @@ public async Task BuildAsync_ShouldSkipJsonFiles_WhenRecurseIntoJsonFilesIsFalse
{ "Key2", "Value2" }
});
File.WriteAllText(Path.Combine(path, "file1.json"), jsonContent);
File.WriteAllText(Path.Combine(path, "file2.txt"), "TextContent");

var result = await _builder.BuildAsync(path, "*.json", SearchOption.TopDirectoryOnly, false, CancellationToken.None);

Assert.Single(result);
Assert.Equal(jsonContent, result["file1"]);

Directory.Delete(path, true);
}

[Fact]
public async Task BuildAsync_ShouldProcessNestedDirectories_WhenSearchOptionIsAllDirectories()
{
var path = "NestedTestFiles";
var nestedPath = Path.Combine(path, "SubDirectory");
Directory.CreateDirectory(nestedPath);
File.WriteAllText(Path.Combine(nestedPath, "file1.txt"), "Content1");

var result = await _builder.BuildAsync(path, "*.txt", SearchOption.AllDirectories, false, CancellationToken.None);

Assert.Single(result);
Assert.Equal("Content1", result["file1"]);
var result = await _builder.BuildAsync(path, "*.*", SearchOption.TopDirectoryOnly, true, CancellationToken.None);

Assert.Equal(3, result.Count);
Assert.Equal("Value1", result["Key1"]);
Assert.Equal("Value2", result["Key2"]);
Assert.Equal("TextContent", result["file2"]);
Directory.Delete(path, true);
}

[Fact]
public async Task BuildAsync_ShouldIgnoreUnsupportedExtensions()
{
// Arrange
var path = "TestFiles";
Directory.CreateDirectory(path);
File.WriteAllText(Path.Combine(path, "file1.unsupported"), "Unsupported Content");

// Act
var result = await _builder.BuildAsync(path, "*.txt", SearchOption.TopDirectoryOnly, false, CancellationToken.None);

// Assert
Assert.Empty(result);

// Clean up
Directory.Delete(path, true);
}

}


}
102 changes: 102 additions & 0 deletions src/KeyValuePush.Tests/DefaultExecutorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using AutoGuru.KeyValuePush;
using Moq;
using Xunit;

namespace KeyValuePush.Tests
{
public class DefaultExecutorTests
{
private readonly Mock<IDictionaryBuilder> _mockDictionaryBuilder;
private readonly Mock<IPusher> _mockPusher;
private readonly DefaultExecutor _executor;

public DefaultExecutorTests()
{
_mockDictionaryBuilder = new Mock<IDictionaryBuilder>();
_mockPusher = new Mock<IPusher>();
_executor = new DefaultExecutor(_mockDictionaryBuilder.Object, _mockPusher.Object);
}

[Fact]
public async Task ExecuteAsync_ShouldReturnZero_WhenSuccessful()
{
// Arrange
var dict = new Dictionary<string, string> { { "key1", "value1" } };
_mockDictionaryBuilder
.Setup(builder => builder.BuildAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<SearchOption>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(dict);
_mockPusher
.Setup(pusher => pusher.PushAsync(It.IsAny<IDictionary<string, string>>(), It.IsAny<CancellationToken>()))
.Returns(Task.CompletedTask);

// Act
var result = await _executor.ExecuteAsync("path", "*.txt", SearchOption.TopDirectoryOnly, false);

// Assert
Assert.Equal(0, result);
}

[Fact]
public async Task ExecuteAsync_ShouldReturnBuilderError_WhenBuildAsyncFails()
{
// Arrange
_mockDictionaryBuilder
.Setup(builder => builder.BuildAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<SearchOption>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new Exception("Build error"));

// Act
var result = await _executor.ExecuteAsync("path", "*.txt", SearchOption.TopDirectoryOnly, false);

// Assert
Assert.Equal((int)DefaultExecutor.ErrorCode.BuilderError, result);
}

[Fact]
public async Task ExecuteAsync_ShouldReturnPusherError_WhenPushAsyncFails()
{
// Arrange
var dict = new Dictionary<string, string> { { "key1", "value1" } };
_mockDictionaryBuilder
.Setup(builder => builder.BuildAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<SearchOption>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(dict);
_mockPusher
.Setup(pusher => pusher.PushAsync(It.IsAny<IDictionary<string, string>>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new Exception("Push error"));

// Act
var result = await _executor.ExecuteAsync("path", "*.txt", SearchOption.TopDirectoryOnly, false);

// Assert
Assert.Equal((int)DefaultExecutor.ErrorCode.PusherError, result);
}

[Fact]
public async Task ExecuteAsync_ShouldLogErrorMessage_WhenExceptionOccurs()
{
// Arrange
var dict = new Dictionary<string, string> { { "key1", "value1" } };
_mockDictionaryBuilder
.Setup(builder => builder.BuildAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<SearchOption>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(dict);
_mockPusher
.Setup(pusher => pusher.PushAsync(It.IsAny<IDictionary<string, string>>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new Exception("Push error"));

using var consoleOutput = new StringWriter();
Console.SetError(consoleOutput);

// Act
await _executor.ExecuteAsync("path", "*.txt", SearchOption.TopDirectoryOnly, false);

// Assert
var output = consoleOutput.ToString();
Assert.Contains("Unexpected error!", output);
Assert.Contains("Push error", output);
}
}
}
Loading

0 comments on commit 9590ac6

Please sign in to comment.