diff --git a/src/LiquidCode.Tester.Worker/Services/PackageParserService.cs b/src/LiquidCode.Tester.Worker/Services/PackageParserService.cs index 3b7b655..5a5cbf1 100644 --- a/src/LiquidCode.Tester.Worker/Services/PackageParserService.cs +++ b/src/LiquidCode.Tester.Worker/Services/PackageParserService.cs @@ -41,20 +41,22 @@ public class PackageParserService : IPackageParserService using var archive = new ZipArchive(packageStream, ZipArchiveMode.Read); archive.ExtractToDirectory(workingDirectory); - // Check if this is a Polygon package (search for problem.xml) + // Search for problem.xml (Polygon package format is required) var problemXmlPath = Directory.EnumerateFiles(workingDirectory, "problem.xml", SearchOption.AllDirectories) .FirstOrDefault(); - if (!string.IsNullOrEmpty(problemXmlPath)) + if (string.IsNullOrEmpty(problemXmlPath)) { - var packageRoot = Path.GetDirectoryName(problemXmlPath)!; - _logger.LogInformation("Detected Polygon package format (problem.xml found at {ProblemXml})", problemXmlPath); - return await ParsePolygonPackageAsync(packageRoot, problemXmlPath, workingDirectory); + _logger.LogError("problem.xml not found in package. Only Polygon format is supported."); + throw new InvalidOperationException( + "Invalid package format: problem.xml not found. " + + "Only Polygon package format is supported. " + + "Please ensure your package contains a problem.xml file."); } - // Fall back to legacy format (.in/.out files) - _logger.LogInformation("Using legacy package format (.in/.out files)"); - return await ParseLegacyPackage(workingDirectory); + var packageRoot = Path.GetDirectoryName(problemXmlPath)!; + _logger.LogInformation("Polygon package detected (problem.xml found at {ProblemXml})", problemXmlPath); + return await ParsePolygonPackageAsync(packageRoot, problemXmlPath, workingDirectory); } catch (Exception ex) { @@ -69,8 +71,18 @@ public class PackageParserService : IPackageParserService if (descriptor == null) { - _logger.LogWarning("Failed to parse problem.xml, falling back to legacy format"); - return await ParseLegacyPackage(packageRoot, extractionRoot); + _logger.LogError("Failed to parse problem.xml"); + throw new InvalidOperationException( + "Failed to parse problem.xml. The Polygon package format may be corrupted or invalid."); + } + + // Check for interactive problems + if (descriptor.Interactor != null) + { + _logger.LogError("Interactive problem detected: {ShortName}", descriptor.ShortName); + throw new NotSupportedException( + "Interactive problems are not currently supported. " + + "The problem package contains an interactor, which is used for interactive tasks."); } var package = new ProblemPackage @@ -99,8 +111,10 @@ public class PackageParserService : IPackageParserService if (testIndices.Count == 0) { - _logger.LogWarning("No test definitions discovered in problem.xml; falling back to filesystem scan"); - return await ParseLegacyPackage(packageRoot, extractionRoot); + _logger.LogError("No test definitions found in problem.xml"); + throw new InvalidOperationException( + "No test definitions found in problem.xml. " + + "The Polygon package must define tests in the problem.xml file."); } var inputs = new List<(int index, string inputPath)>(); @@ -195,60 +209,6 @@ public class PackageParserService : IPackageParserService return package; } - private async Task ParseLegacyPackage(string workingDirectory, string? extractionRoot = null) - { - var package = new ProblemPackage - { - WorkingDirectory = workingDirectory, - ExtractionRoot = extractionRoot ?? 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 = package.TestCases.Count + 1, - InputFilePath = inputFile, - OutputFilePath = outputFile, - TimeLimit = package.DefaultTimeLimit, - MemoryLimit = package.DefaultMemoryLimit - }); - } - - // Look for and compile checker - package.CheckerPath = await FindAndCompileCheckerAsync(workingDirectory); - - if (package.TestCases.Count == 0) - { - _logger.LogWarning("No test cases found! Check package structure. Expected .in/.out files in tests directory or root"); - } - - _logger.LogInformation("Parsed legacy package with {TestCount} tests", package.TestCases.Count); - return package; - } private async Task> CompilePolygonExecutablesAsync( PolygonProblemDescriptor descriptor, @@ -691,36 +651,6 @@ public class PackageParserService : IPackageParserService return null; } - 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; - } private async Task FindAndCompileCheckerAsync(string workingDirectory) { diff --git a/src/LiquidCode.Tester.Worker/Services/PolygonProblemXmlParser.cs b/src/LiquidCode.Tester.Worker/Services/PolygonProblemXmlParser.cs index c9b2212..a765c3f 100644 --- a/src/LiquidCode.Tester.Worker/Services/PolygonProblemXmlParser.cs +++ b/src/LiquidCode.Tester.Worker/Services/PolygonProblemXmlParser.cs @@ -210,6 +210,21 @@ public class PolygonProblemXmlParser } } + var interactorElement = assets.Element("interactor"); + if (interactorElement != null) + { + var interactorSource = interactorElement.Element("source"); + if (interactorSource != null) + { + descriptor.Interactor = new PolygonInteractorDescriptor + { + SourcePath = interactorSource.Attribute("path")?.Value ?? string.Empty, + Type = interactorSource.Attribute("type")?.Value, + BinaryPath = interactorElement.Element("binary")?.Attribute("path")?.Value + }; + } + } + var validatorsSection = assets.Element("validators"); if (validatorsSection != null) { @@ -264,6 +279,7 @@ public class PolygonProblemDescriptor public List Tests { get; } = new(); public List Executables { get; } = new(); public PolygonCheckerDescriptor? Checker { get; set; } + public PolygonInteractorDescriptor? Interactor { get; set; } public List Validators { get; } = new(); } @@ -311,6 +327,16 @@ public class PolygonCheckerDescriptor public string? Type { get; set; } } +/// +/// Represents interactor information declared in problem.xml +/// +public class PolygonInteractorDescriptor +{ + public string SourcePath { get; set; } = string.Empty; + public string? BinaryPath { get; set; } + public string? Type { get; set; } +} + /// /// Represents validator information declared in problem.xml ///