diff --git a/src/main/java/com/cp/compiler/contract/RemoteCodeCompilerExecutionResponse.java b/src/main/java/com/cp/compiler/contract/RemoteCodeCompilerExecutionResponse.java index f63ebb6..015ed22 100644 --- a/src/main/java/com/cp/compiler/contract/RemoteCodeCompilerExecutionResponse.java +++ b/src/main/java/com/cp/compiler/contract/RemoteCodeCompilerExecutionResponse.java @@ -3,8 +3,8 @@ import com.cp.compiler.contract.testcases.TestCaseResult; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.Data; import lombok.EqualsAndHashCode; -import lombok.Getter; import lombok.NoArgsConstructor; import java.time.LocalDateTime; @@ -19,7 +19,7 @@ * * @author Zakaria Maaraki */ -@Getter +@Data @NoArgsConstructor @EqualsAndHashCode @ApiModel(description = "The returned response") diff --git a/src/main/java/com/cp/compiler/contract/RemoteCodeCompilerResponse.java b/src/main/java/com/cp/compiler/contract/RemoteCodeCompilerResponse.java index 2dc1ab7..2e0e100 100644 --- a/src/main/java/com/cp/compiler/contract/RemoteCodeCompilerResponse.java +++ b/src/main/java/com/cp/compiler/contract/RemoteCodeCompilerResponse.java @@ -1,12 +1,9 @@ package com.cp.compiler.contract; import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; -@Getter +@Data @NoArgsConstructor @EqualsAndHashCode @AllArgsConstructor diff --git a/src/test/java/com/cp/compiler/repositories/ProblemsRepositoryTests.java b/src/test/java/com/cp/compiler/repositories/ProblemsRepositoryTests.java new file mode 100644 index 0000000..445b39e --- /dev/null +++ b/src/test/java/com/cp/compiler/repositories/ProblemsRepositoryTests.java @@ -0,0 +1,121 @@ +package com.cp.compiler.repositories; + +import com.cp.compiler.contract.problems.Difficulty; +import com.cp.compiler.contract.problems.Problem; +import com.cp.compiler.exceptions.problems.InvalidProblemException; +import com.cp.compiler.exceptions.problems.ProblemNotFoundException; +import com.cp.compiler.repositories.problems.ProblemsRepositoryDefault; +import com.fasterxml.jackson.core.type.TypeReference; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class ProblemsRepositoryTests { + + @Mock + private TypeReference> typeReference; + + @InjectMocks + private ProblemsRepositoryDefault problemsRepository; + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + ReflectionTestUtils.setField(problemsRepository, "problems", new HashMap<>()); + } + + @Test + void getProblemById_ExistingProblem_ReturnsProblem() { + // Arrange + long problemId = 1L; + Problem expectedProblem = createSampleProblem(problemId); + callInit(2); + + // Act + Problem actualProblem = problemsRepository.getProblemById(problemId); + + // Assert + assertEquals(expectedProblem, actualProblem); + } + + @Test + void getProblemById_NonExistingProblem_ThrowsProblemNotFoundException() { + // Arrange + long nonExistingProblemId = 99L; + callInit(1); + + // Act and Assert + assertThrows(ProblemNotFoundException.class, () -> problemsRepository.getProblemById(nonExistingProblemId)); + } + + @Test + void getAllProblems_ReturnsAllProblems() { + // Arrange + List expectedProblems = createSampleProblems(2); + callInit(2); + + // Act + List actualProblems = problemsRepository.getAllProblems(); + + // Assert + assertEquals(expectedProblems.size(), actualProblems.size()); + + for (int i = 0; i < actualProblems.size(); i++) { + assertEquals(actualProblems.get(i), expectedProblems.get(i)); + } + } + + @Test + void init_ValidProblems_LoadsProblems() { + // Act + callInit(1); + + // Assert + HashMap loadedProblems = (HashMap) ReflectionTestUtils.getField(problemsRepository, "problems"); + assertNotNull(loadedProblems); + assertFalse(loadedProblems.isEmpty()); + } + + private void callInit(int problemsCount) { + // Access the problems field using reflection and update it + HashMap problems = (HashMap) ReflectionTestUtils.getField(problemsRepository, "problems"); + problems.clear(); + + for (int i = 0; i < problemsCount; i++) { + Problem createdProblem = createSampleProblem(i); + problems.put((long)i, createdProblem); + } + } + + + + private Problem createSampleProblem(long problemId) { + return Problem.builder() + .id(problemId) + .title("Sample Problem") + .description("This is a sample problem.") + .timeLimit(1000) + .memoryLimit(256) + .testCases(new ArrayList<>()) + .tags(List.of("tag1", "tag2")) + .difficulty(Difficulty.MEDIUM) + .build(); + } + + private List createSampleProblems(int count) { + List problems = new ArrayList<>(); + for (long i = 0; i < count; i++) { + problems.add(createSampleProblem(i)); + } + return problems; + } +} \ No newline at end of file diff --git a/src/test/java/com/cp/compiler/services/ux/ExecutionServiceDefaultTests.java b/src/test/java/com/cp/compiler/services/ux/ExecutionServiceDefaultTests.java new file mode 100644 index 0000000..a3f7f19 --- /dev/null +++ b/src/test/java/com/cp/compiler/services/ux/ExecutionServiceDefaultTests.java @@ -0,0 +1,186 @@ +package com.cp.compiler.services.ux; + +import com.cp.compiler.contract.Language; +import com.cp.compiler.contract.RemoteCodeCompilerExecutionResponse; +import com.cp.compiler.contract.RemoteCodeCompilerRequest; +import com.cp.compiler.contract.RemoteCodeCompilerResponse; +import com.cp.compiler.contract.problems.Difficulty; +import com.cp.compiler.contract.problems.Problem; +import com.cp.compiler.contract.problems.ProblemExecution; +import com.cp.compiler.contract.testcases.TestCase; +import com.cp.compiler.contract.testcases.TestCaseResult; +import com.cp.compiler.executions.Execution; +import com.cp.compiler.executions.ExecutionFactory; +import com.cp.compiler.executions.languages.JavaExecution; +import com.cp.compiler.models.Verdict; +import com.cp.compiler.models.testcases.TransformedTestCase; +import com.cp.compiler.repositories.problems.ProblemsRepository; +import com.cp.compiler.services.api.CompilerFacade; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class ExecutionServiceDefaultTests { + + @Mock + private CompilerFacade compiler; + + @Mock + private ProblemsRepository problemsRepository; + + @InjectMocks + private ExecutionServiceDefault executionService; + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + + ExecutionFactory.registerExecution( + Language.JAVA, + (MultipartFile sourceCode, List testCases, int timeLimit, int memoryLimit) -> new JavaExecution( + sourceCode, + testCases, + timeLimit, + memoryLimit)); + } + + @Test + void execute_ValidProblem_ReturnsCompilerResponse() throws IOException { + // Arrange + long problemId = 1L; + Problem problem = createSampleProblem(problemId); + ProblemExecution problemExecution = createSampleProblemExecution(problemId); + RemoteCodeCompilerRequest expectedRequest = createSampleCompilerRequest(problem, problemExecution); + Execution expectedExecution = createSampleExecution(expectedRequest); + + when(problemsRepository.getProblemById(problemId)).thenReturn(problem); + when(compiler.compile(any(), eq(false), eq(null), eq(null))).thenReturn(createSampleCompilerResponse(expectedRequest)); + + // Act + ResponseEntity responseEntity = executionService.execute(problemExecution); + + // Assert + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + RemoteCodeCompilerResponse compilerResponse = responseEntity.getBody(); + assertNotNull(compilerResponse); + assertEquals(expectedRequest.getLanguage(), compilerResponse.getExecution().getLanguage()); + assertEquals(expectedRequest.getTimeLimit(), compilerResponse.getExecution().getTimeLimit()); + assertEquals(expectedRequest.getMemoryLimit(), compilerResponse.getExecution().getMemoryLimit()); + assertEquals(Verdict.ACCEPTED.getStatusResponse(), compilerResponse.getExecution().getVerdict()); + + Map testCasesResult = compilerResponse.getExecution().getTestCasesResult(); + assertNotNull(testCasesResult); + assertEquals(2, testCasesResult.size()); + + int index = 0; + for (TestCaseResult testCaseResult : testCasesResult.values()) { + if (index++ < 2) { + assertNotNull(testCaseResult.getExpectedOutput()); + } else { + assertEquals("**Hidden**", testCaseResult.getExpectedOutput()); + assertEquals("**Hidden**", testCaseResult.getOutputDiff()); + } + } + } + + private Problem createSampleProblem(long problemId) { + return Problem.builder() + .id(problemId) + .title("Sample Problem " + problemId) + .description("Description of Sample Problem " + problemId) + .difficulty(Difficulty.MEDIUM) + .tags(Arrays.asList("tag1", "tag2")) + .testCases(Arrays.asList( + new TestCase("input1", "output1"), + new TestCase("input2", "output2"), + new TestCase("input3", "output3") + )) + .timeLimit(1000) + .memoryLimit(256) + .build(); + } + + private ProblemExecution createSampleProblemExecution(long problemId) { + return new ProblemExecution( + problemId, + "Sample source code", + Language.JAVA); + } + + private RemoteCodeCompilerRequest createSampleCompilerRequest(Problem problem, ProblemExecution problemExecution) { + LinkedHashMap testCases = new LinkedHashMap<>(); + int index = 0; + + for (TestCase testCase : problem.getTestCases()) { + testCases.put(String.valueOf(index++), testCase); + } + + return new RemoteCodeCompilerRequest( + problemExecution.getSourceCode(), + problemExecution.getLanguage(), + problem.getTimeLimit(), + problem.getMemoryLimit(), + testCases); + } + + private Execution createSampleExecution(RemoteCodeCompilerRequest compilerRequest) throws IOException { + return ExecutionFactory.createExecution( + compilerRequest.getSourcecodeFile(), + compilerRequest.getConvertedTestCases(), + compilerRequest.getTimeLimit(), + compilerRequest.getMemoryLimit(), + compilerRequest.getLanguage()); + } + + private ResponseEntity createSampleCompilerResponse(RemoteCodeCompilerRequest compilerRequest) { + var execution = new RemoteCodeCompilerExecutionResponse(); + execution.setLanguage(compilerRequest.getLanguage()); + execution.setTimeLimit(compilerRequest.getTimeLimit()); + execution.setMemoryLimit(compilerRequest.getMemoryLimit()); + execution.setVerdict(Verdict.ACCEPTED.getStatusResponse()); + + // Create two sample TestCaseResult instances + TestCaseResult testCaseResult1 = new TestCaseResult( + Verdict.ACCEPTED, + "Sample Output 1", + null, + "Expected Output 1", + 1000 + ); + + TestCaseResult testCaseResult2 = new TestCaseResult( + Verdict.WRONG_ANSWER, + "Sample Output 2", + null, + "Expected Output 2", + 1500 + ); + + execution.setTestCasesResult(new LinkedHashMap<>()); + execution.getTestCasesResult().put("0", testCaseResult1); + execution.getTestCasesResult().put("1", testCaseResult2); + + RemoteCodeCompilerResponse compilerResponse = new RemoteCodeCompilerResponse(); + compilerResponse.setExecution(execution); + + return new ResponseEntity<>(compilerResponse, HttpStatus.OK); + } +} diff --git a/src/test/java/com/cp/compiler/services/ux/ProblemLoaderTests.java b/src/test/java/com/cp/compiler/services/ux/ProblemLoaderTests.java new file mode 100644 index 0000000..2c8f66d --- /dev/null +++ b/src/test/java/com/cp/compiler/services/ux/ProblemLoaderTests.java @@ -0,0 +1,111 @@ +package com.cp.compiler.services.ux; + +import com.cp.compiler.contract.problems.Difficulty; +import com.cp.compiler.contract.problems.Problem; +import com.cp.compiler.contract.testcases.TestCase; +import com.cp.compiler.exceptions.problems.ProblemNotFoundException; +import com.cp.compiler.repositories.problems.ProblemsRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +public class ProblemLoaderTests { + + @Mock + private ProblemsRepository problemsRepository; + + @InjectMocks + private ProblemLoaderDefault problemLoader; + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + void getProblemById_ExistingProblem_ReturnsTransformedProblem() { + // Arrange + long problemId = 1L; + Problem originalProblem = createSampleProblem(problemId); + when(problemsRepository.getProblemById(problemId)).thenReturn(originalProblem); + + // Act + Problem transformedProblem = problemLoader.getProblemById(problemId); + + // Assert + assertNotSame(originalProblem, transformedProblem); + assertEquals(originalProblem.getId(), transformedProblem.getId()); + assertEquals(originalProblem.getTitle(), transformedProblem.getTitle()); + assertEquals(originalProblem.getDescription(), transformedProblem.getDescription()); + assertEquals(originalProblem.getDifficulty(), transformedProblem.getDifficulty()); + assertEquals(originalProblem.getTags(), transformedProblem.getTags()); + assertEquals(originalProblem.getTestCases().subList(0, 2), transformedProblem.getTestCases()); + assertEquals(originalProblem.getTimeLimit(), transformedProblem.getTimeLimit()); + assertEquals(originalProblem.getMemoryLimit(), transformedProblem.getMemoryLimit()); + } + + @Test + void getProblemById_NonExistingProblem_ThrowsProblemNotFoundException() { + // Arrange + long nonExistingProblemId = 99L; + when(problemsRepository.getProblemById(nonExistingProblemId)) + .thenThrow(new ProblemNotFoundException("Problem not found")); + + // Act and Assert + assertThrows(ProblemNotFoundException.class, () -> problemLoader.getProblemById(nonExistingProblemId)); + } + + @Test + void getAllProblems_ReturnsTransformedProblemsList() { + // Arrange + List originalProblems = + Arrays.asList(createSampleProblem(1L), createSampleProblem(2L)); + when(problemsRepository.getAllProblems()).thenReturn(originalProblems); + + // Act + List transformedProblems = problemLoader.getAllProblems(); + + // Assert + assertNotSame(originalProblems, transformedProblems); + assertEquals(originalProblems.size(), transformedProblems.size()); + + for (int i = 0; i < originalProblems.size(); i++) { + Problem originalProblem = originalProblems.get(i); + Problem transformedProblem = transformedProblems.get(i); + + assertEquals(originalProblem.getId(), transformedProblem.getId()); + assertEquals(originalProblem.getTitle(), transformedProblem.getTitle()); + assertEquals(originalProblem.getDescription(), transformedProblem.getDescription()); + assertEquals(originalProblem.getDifficulty(), transformedProblem.getDifficulty()); + assertEquals(originalProblem.getTags(), transformedProblem.getTags()); + assertEquals(originalProblem.getTestCases().subList(0, 2), transformedProblem.getTestCases()); + assertEquals(originalProblem.getTimeLimit(), transformedProblem.getTimeLimit()); + assertEquals(originalProblem.getMemoryLimit(), transformedProblem.getMemoryLimit()); + } + } + + private Problem createSampleProblem(long problemId) { + return Problem.builder() + .id(problemId) + .title("Sample Problem " + problemId) + .description("Description of Sample Problem " + problemId) + .difficulty(Difficulty.MEDIUM) + .tags(Arrays.asList("tag1", "tag2")) + .testCases(Arrays.asList( + new TestCase("input1", "output1"), + new TestCase("input2", "output2"), + new TestCase("input3", "output3") + )) + .timeLimit(1000) + .memoryLimit(256) + .build(); + } +} \ No newline at end of file