add compile & test worker

This commit is contained in:
prixod
2025-10-24 23:46:51 +04:00
parent 3d854c3470
commit 6cead15a5f
19 changed files with 849 additions and 13 deletions

View File

@@ -0,0 +1,120 @@
using System.IO.Compression;
using LiquidCode.Tester.Common.Models;
namespace LiquidCode.Tester.Worker.Services;
public class PackageParserService : IPackageParserService
{
private readonly ILogger<PackageParserService> _logger;
public PackageParserService(ILogger<PackageParserService> logger)
{
_logger = logger;
}
public async Task<ProblemPackage> ParsePackageAsync(Stream packageStream)
{
var workingDirectory = Path.Combine(Path.GetTempPath(), $"problem_{Guid.NewGuid()}");
Directory.CreateDirectory(workingDirectory);
_logger.LogInformation("Extracting package to {WorkingDirectory}", workingDirectory);
try
{
// Extract ZIP archive
using var archive = new ZipArchive(packageStream, ZipArchiveMode.Read);
archive.ExtractToDirectory(workingDirectory);
var package = new ProblemPackage
{
WorkingDirectory = workingDirectory
};
// Find tests directory
var testsDir = Path.Combine(workingDirectory, "tests");
if (!Directory.Exists(testsDir))
{
_logger.LogWarning("Tests directory not found, searching for test files in root");
testsDir = workingDirectory;
}
// Parse test cases
var inputFiles = Directory.GetFiles(testsDir, "*", SearchOption.AllDirectories)
.Where(f => Path.GetFileName(f).EndsWith(".in") || Path.GetFileName(f).Contains("input"))
.OrderBy(f => f)
.ToList();
for (int i = 0; i < inputFiles.Count; i++)
{
var inputFile = inputFiles[i];
var outputFile = FindCorrespondingOutputFile(inputFile);
if (outputFile == null)
{
_logger.LogWarning("No output file found for input {InputFile}", inputFile);
continue;
}
package.TestCases.Add(new TestCase
{
Number = i + 1,
InputFilePath = inputFile,
OutputFilePath = outputFile,
TimeLimit = package.DefaultTimeLimit,
MemoryLimit = package.DefaultMemoryLimit
});
}
// Look for checker
var checkerCandidates = new[] { "check.cpp", "checker.cpp", "check", "checker" };
foreach (var candidate in checkerCandidates)
{
var checkerPath = Path.Combine(workingDirectory, candidate);
if (File.Exists(checkerPath))
{
package.CheckerPath = checkerPath;
break;
}
}
_logger.LogInformation("Parsed package with {TestCount} tests", package.TestCases.Count);
return package;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to parse package");
throw;
}
}
private string? FindCorrespondingOutputFile(string inputFile)
{
var directory = Path.GetDirectoryName(inputFile)!;
var fileName = Path.GetFileNameWithoutExtension(inputFile);
var extension = Path.GetExtension(inputFile);
// Try various output file naming patterns
var patterns = new[]
{
fileName.Replace("input", "output") + ".out",
fileName.Replace("input", "output") + ".a",
fileName.Replace("input", "answer") + ".out",
fileName.Replace("input", "answer") + ".a",
fileName + ".out",
fileName + ".a",
fileName.Replace(".in", ".out"),
fileName.Replace(".in", ".a")
};
foreach (var pattern in patterns)
{
var candidate = Path.Combine(directory, pattern);
if (File.Exists(candidate))
{
return candidate;
}
}
return null;
}
}