using System.IO.Compression; using LiquidCode.Tester.Worker.Services; using Microsoft.Extensions.Logging; using Moq; namespace LiquidCode.Tester.Worker.Tests; public class PackageParserServiceTests : IDisposable { private readonly PackageParserService _service; private readonly string _testDirectory; public PackageParserServiceTests() { var logger = new Mock>(); var xmlLogger = new Mock>(); var answerGenLogger = new Mock>(); var cppLogger = new Mock>(); var cppConfigMock = new Mock(); var polygonParser = new PolygonProblemXmlParser(xmlLogger.Object); var compilationFactory = new Mock(); var executionFactory = new Mock(); var answerGenerator = new AnswerGenerationService( compilationFactory.Object, executionFactory.Object, answerGenLogger.Object); var cppCompilation = new CppCompilationService(cppLogger.Object, cppConfigMock.Object); _service = new PackageParserService(logger.Object, polygonParser, answerGenerator, cppCompilation); _testDirectory = Path.Combine(Path.GetTempPath(), "PackageParserTests", Guid.NewGuid().ToString()); Directory.CreateDirectory(_testDirectory); } [Fact] public async Task ParsePackageAsync_ValidPackageWithTestCases_ParsesSuccessfully() { // Arrange var zipStream = CreateTestPackage(new[] { ("1.in", "input1"), ("1.out", "output1"), ("2.in", "input2"), ("2.out", "output2"), ("3.in", "input3"), ("3.out", "output3") }); // Act var result = await _service.ParsePackageAsync(zipStream); // Assert Assert.NotNull(result); Assert.Equal(3, result.TestCases.Count); Assert.True(Directory.Exists(result.WorkingDirectory)); // Check test case 1 Assert.Equal(1, result.TestCases[0].Number); Assert.True(File.Exists(result.TestCases[0].InputFilePath)); Assert.True(File.Exists(result.TestCases[0].OutputFilePath)); Assert.Equal("input1", await File.ReadAllTextAsync(result.TestCases[0].InputFilePath)); // Check test case 2 Assert.Equal(2, result.TestCases[1].Number); Assert.True(File.Exists(result.TestCases[1].InputFilePath)); Assert.True(File.Exists(result.TestCases[1].OutputFilePath)); // Check test case 3 Assert.Equal(3, result.TestCases[2].Number); Assert.True(File.Exists(result.TestCases[2].InputFilePath)); Assert.True(File.Exists(result.TestCases[2].OutputFilePath)); } [Fact] public async Task ParsePackageAsync_PackageWithDefaultLimits_UsesDefaultValues() { // Arrange var zipStream = CreateTestPackage(new[] { ("1.in", "input1"), ("1.out", "output1") }); // Act var result = await _service.ParsePackageAsync(zipStream); // Assert Assert.Single(result.TestCases); Assert.Equal(2000, result.TestCases[0].TimeLimit); // Default time limit Assert.Equal(256, result.TestCases[0].MemoryLimit); // Default memory limit } [Fact] public async Task ParsePackageAsync_EmptyPackage_ReturnsEmptyTestCasesList() { // Arrange var zipStream = CreateTestPackage(Array.Empty<(string, string)>()); // Act var result = await _service.ParsePackageAsync(zipStream); // Assert Assert.NotNull(result); Assert.Empty(result.TestCases); } [Fact] public async Task ParsePackageAsync_TestCasesNotInOrder_SortsCorrectly() { // Arrange var zipStream = CreateTestPackage(new[] { ("3.in", "input3"), ("3.out", "output3"), ("1.in", "input1"), ("1.out", "output1"), ("2.in", "input2"), ("2.out", "output2") }); // Act var result = await _service.ParsePackageAsync(zipStream); // Assert Assert.Equal(3, result.TestCases.Count); Assert.Equal(1, result.TestCases[0].Number); Assert.Equal(2, result.TestCases[1].Number); Assert.Equal(3, result.TestCases[2].Number); } [Fact] public async Task ParsePackageAsync_MissingOutputFile_SkipsTestCase() { // Arrange var zipStream = CreateTestPackage(new[] { ("1.in", "input1"), ("1.out", "output1"), ("2.in", "input2"), // Missing 2.out ("3.in", "input3"), ("3.out", "output3") }); // Act var result = await _service.ParsePackageAsync(zipStream); // Assert Assert.Equal(2, result.TestCases.Count); // Only test 1 and 3 Assert.Equal(1, result.TestCases[0].Number); Assert.Equal(3, result.TestCases[1].Number); } [Fact] public async Task ParsePackageAsync_MissingInputFile_SkipsTestCase() { // Arrange var zipStream = CreateTestPackage(new[] { ("1.in", "input1"), ("1.out", "output1"), // Missing 2.in ("2.out", "output2"), ("3.in", "input3"), ("3.out", "output3") }); // Act var result = await _service.ParsePackageAsync(zipStream); // Assert Assert.Equal(2, result.TestCases.Count); // Only test 1 and 3 Assert.Equal(1, result.TestCases[0].Number); Assert.Equal(3, result.TestCases[1].Number); } [Fact] public async Task ParsePackageAsync_TestsInSubdirectory_ParsesSuccessfully() { // Arrange var zipStream = CreateTestPackage(new[] { ("tests/1.in", "input1"), ("tests/1.out", "output1"), ("tests/2.in", "input2"), ("tests/2.out", "output2") }); // Act var result = await _service.ParsePackageAsync(zipStream); // Assert Assert.Equal(2, result.TestCases.Count); Assert.Equal(1, result.TestCases[0].Number); Assert.Equal(2, result.TestCases[1].Number); } private MemoryStream CreateTestPackage(IEnumerable<(string fileName, string content)> files) { var memoryStream = new MemoryStream(); using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) { foreach (var (fileName, content) in files) { var entry = archive.CreateEntry(fileName); using var entryStream = entry.Open(); using var writer = new StreamWriter(entryStream); writer.Write(content); } } memoryStream.Position = 0; return memoryStream; } public void Dispose() { if (Directory.Exists(_testDirectory)) { Directory.Delete(_testDirectory, true); } } }