Files
LiquidCode.Tester/src/LiquidCode.Tester.Worker/Services/OutputCheckerService.cs
2025-10-28 22:03:50 +04:00

88 lines
2.8 KiB
C#

namespace LiquidCode.Tester.Worker.Services;
public class OutputCheckerService : IOutputCheckerService
{
private readonly ILogger<OutputCheckerService> _logger;
private readonly CheckerService _checkerService;
public OutputCheckerService(ILogger<OutputCheckerService> logger, CheckerService checkerService)
{
_logger = logger;
_checkerService = checkerService;
}
public async Task<bool> CheckOutputAsync(string actualOutput, string expectedOutputPath)
{
try
{
var expectedOutput = await File.ReadAllTextAsync(expectedOutputPath);
// Normalize outputs for comparison
var normalizedActual = NormalizeOutput(actualOutput);
var normalizedExpected = NormalizeOutput(expectedOutput);
var match = normalizedActual == normalizedExpected;
if (!match)
{
_logger.LogDebug("Output mismatch. Expected length: {ExpectedLength}, Actual length: {ActualLength}",
normalizedExpected.Length, normalizedActual.Length);
}
return match;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error checking output against {ExpectedFile}", expectedOutputPath);
return false;
}
}
private string NormalizeOutput(string output)
{
// Remove trailing whitespace from each line and normalize line endings
var lines = output.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
.Select(line => line.TrimEnd())
.ToList();
// Remove trailing empty lines
while (lines.Count > 0 && string.IsNullOrWhiteSpace(lines[^1]))
{
lines.RemoveAt(lines.Count - 1);
}
return string.Join("\n", lines);
}
public async Task<bool> CheckOutputWithCheckerAsync(
string actualOutput,
string inputFilePath,
string expectedOutputPath,
string? checkerPath)
{
// If custom checker is available, use it
if (!string.IsNullOrEmpty(checkerPath) && File.Exists(checkerPath))
{
_logger.LogDebug("Using custom checker: {CheckerPath}", checkerPath);
var checkerResult = await _checkerService.CheckAsync(
checkerPath,
inputFilePath,
actualOutput,
expectedOutputPath);
if (!checkerResult.Accepted)
{
_logger.LogWarning("Custom checker verdict: {Verdict} - {Message}",
checkerResult.Verdict, checkerResult.Message);
}
return checkerResult.Accepted;
}
// Fall back to standard string comparison
_logger.LogDebug("No custom checker, using standard comparison");
return await CheckOutputAsync(actualOutput, expectedOutputPath);
}
}