using System.Diagnostics; using System.IO; using System.IO.Compression; using LiquidCode.Tester.Worker.Services; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Abstractions; using Xunit; namespace LiquidCode.Tester.Worker.Tests; public class PolygonPackageIntegrationTests { private readonly PackageParserService _parserService; public PolygonPackageIntegrationTests() { var configuration = new ConfigurationBuilder().Build(); var cppCompilation = new CppCompilationService(NullLogger.Instance, configuration); var cppExecution = new CppExecutionService(NullLogger.Instance); var services = new ServiceCollection(); services.AddSingleton(configuration); services.AddSingleton(cppCompilation); services.AddSingleton(cppExecution); var serviceProvider = services.BuildServiceProvider(); var compilationFactory = new CompilationServiceFactory(serviceProvider, NullLogger.Instance); var executionFactory = new ExecutionServiceFactory(serviceProvider, NullLogger.Instance); var answerGenerator = new AnswerGenerationService(compilationFactory, executionFactory, NullLogger.Instance); var polygonParser = new PolygonProblemXmlParser(NullLogger.Instance); _parserService = new PackageParserService( NullLogger.Instance, polygonParser, answerGenerator, cppCompilation); } [Fact] public async Task ParsePolygonPackageAsync_GeneratesTestsCheckerAndAnswers() { if (!IsExecutableAvailable("g++")) { return; } var packageDirectory = ResolvePackageDirectory("exam-queue-17"); Assert.True(Directory.Exists(packageDirectory)); await using var packageStream = CreateZipFromDirectory(packageDirectory); var package = await _parserService.ParsePackageAsync(packageStream); try { Assert.Equal(51, package.TestCases.Count); Assert.NotNull(package.CheckerPath); Assert.True(File.Exists(package.CheckerPath), $"Checker not present at {package.CheckerPath}"); foreach (var testCase in package.TestCases) { Assert.True(File.Exists(testCase.InputFilePath), $"Missing input {testCase.InputFilePath}"); Assert.True(File.Exists(testCase.OutputFilePath), $"Missing output {testCase.OutputFilePath}"); Assert.True(new FileInfo(testCase.InputFilePath).Length > 0); Assert.True(new FileInfo(testCase.OutputFilePath).Length > 0); } } finally { if (!string.IsNullOrEmpty(package.ExtractionRoot) && Directory.Exists(package.ExtractionRoot)) { Directory.Delete(package.ExtractionRoot, recursive: true); } else if (Directory.Exists(package.WorkingDirectory)) { Directory.Delete(package.WorkingDirectory, recursive: true); } } } private static bool IsExecutableAvailable(string executable) { try { using var process = new Process { StartInfo = new ProcessStartInfo { FileName = executable, Arguments = "--version", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true } }; process.Start(); if (!process.WaitForExit(5000)) { try { process.Kill(entireProcessTree: true); } catch { // ignored } return false; } return process.ExitCode == 0; } catch { return false; } } private static MemoryStream CreateZipFromDirectory(string directoryPath) { var memoryStream = new MemoryStream(); using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, leaveOpen: true)) { foreach (var file in Directory.GetFiles(directoryPath, "*", SearchOption.AllDirectories)) { var entryName = Path.GetRelativePath(directoryPath, file).Replace("\\", "/"); var entry = archive.CreateEntry(entryName, CompressionLevel.Fastest); using (var entryStream = entry.Open()) using (var fileStream = File.OpenRead(file)) { fileStream.CopyTo(entryStream); } } } memoryStream.Position = 0; return memoryStream; } private static string ResolvePackageDirectory(string folderName) { var baseDirectory = AppContext.BaseDirectory; var root = Path.GetFullPath(Path.Combine(baseDirectory, "..", "..", "..", "..", "..")); return Path.Combine(root, folderName); } }