diff --git a/src/main/java/fr/univ_lille/gitlab/classrooms/ui/QuizController.java b/src/main/java/fr/univ_lille/gitlab/classrooms/quiz/QuizAnswerController.java similarity index 59% rename from src/main/java/fr/univ_lille/gitlab/classrooms/ui/QuizController.java rename to src/main/java/fr/univ_lille/gitlab/classrooms/quiz/QuizAnswerController.java index c63c3b0..24f40c4 100644 --- a/src/main/java/fr/univ_lille/gitlab/classrooms/ui/QuizController.java +++ b/src/main/java/fr/univ_lille/gitlab/classrooms/quiz/QuizAnswerController.java @@ -1,8 +1,5 @@ -package fr.univ_lille.gitlab.classrooms.ui; +package fr.univ_lille.gitlab.classrooms.quiz; -import fr.univ_lille.gitlab.classrooms.quiz.*; -import jakarta.annotation.security.RolesAllowed; -import org.springframework.data.domain.Sort; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.core.Authentication; @@ -15,51 +12,17 @@ import java.util.Map; @Controller @RequestMapping("/quiz") -public class QuizController { - - private static final String QUIZ_LIST_PAGE = "quiz/list"; - private static final String QUIZ_EDIT_PAGE = "quiz/edit"; +public class QuizAnswerController { QuizRepository quizRepository; QuizScoreService quizScoreService; - public QuizController(QuizScoreService quizScoreService, QuizRepository quizRepository) { + public QuizAnswerController(QuizScoreService quizScoreService, QuizRepository quizRepository) { this.quizScoreService = quizScoreService; this.quizRepository = quizRepository; } - @GetMapping("") - @RolesAllowed("TEACHER") - public String listQuiz(Model model) { - model.addAttribute("quizzes", this.quizRepository.findAll(Sort.by("name"))); - return QUIZ_LIST_PAGE; - } - - @GetMapping("/new/edit") - @RolesAllowed("TEACHER") - public String newQuiz(Model model) { - model.addAttribute("quiz", new QuizEntity()); - return QUIZ_EDIT_PAGE; - } - - @GetMapping("/{quizId}/edit") - @RolesAllowed("TEACHER") - public String editQuiz(Model model, @PathVariable String quizId) { - var quizEntity = this.quizRepository.findById(quizId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - model.addAttribute("quiz", quizEntity); - return QUIZ_EDIT_PAGE; - } - - @PostMapping("/{quizId}/edit") - @RolesAllowed("TEACHER") - public String saveQuiz(@ModelAttribute QuizEntity quiz, Model model, @PathVariable String quizId) { - this.quizRepository.save(quiz); - model.addAttribute("quiz", quiz); - model.addAttribute("successMessage", "Quiz successfully saved"); - return QUIZ_EDIT_PAGE; - } - @GetMapping("/{quizId}") public String showQuiz(Model model, @PathVariable String quizId, Authentication authentication) { var quizEntity = this.quizRepository.findById(quizId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); @@ -99,5 +62,4 @@ public class QuizController { model.addAttribute("quiz", quiz); return "quiz-submitted-with-answers-correction"; } - } diff --git a/src/main/java/fr/univ_lille/gitlab/classrooms/quiz/QuizEditionController.java b/src/main/java/fr/univ_lille/gitlab/classrooms/quiz/QuizEditionController.java new file mode 100644 index 0000000..ea750ad --- /dev/null +++ b/src/main/java/fr/univ_lille/gitlab/classrooms/quiz/QuizEditionController.java @@ -0,0 +1,54 @@ +package fr.univ_lille.gitlab.classrooms.quiz; + +import jakarta.annotation.security.RolesAllowed; +import org.springframework.data.domain.Sort; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +@Controller +@RequestMapping("/quiz") +@RolesAllowed("TEACHER") +public class QuizEditionController { + + private static final String QUIZ_LIST_PAGE = "quiz/list"; + private static final String QUIZ_EDIT_PAGE = "quiz/edit"; + + QuizRepository quizRepository; + + QuizScoreService quizScoreService; + + public QuizEditionController(QuizScoreService quizScoreService, QuizRepository quizRepository) { + this.quizScoreService = quizScoreService; + this.quizRepository = quizRepository; + } + + @GetMapping("") + public String listQuiz(Model model) { + model.addAttribute("quizzes", this.quizRepository.findAll(Sort.by("name"))); + return QUIZ_LIST_PAGE; + } + + @GetMapping("/new/edit") + public String newQuiz(Model model) { + model.addAttribute("quiz", new QuizEntity()); + return QUIZ_EDIT_PAGE; + } + + @GetMapping("/{quizId}/edit") + public String editQuiz(Model model, @PathVariable String quizId) { + var quizEntity = this.quizRepository.findById(quizId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + model.addAttribute("quiz", quizEntity); + return QUIZ_EDIT_PAGE; + } + + @PostMapping("/{quizId}/edit") + public String saveQuiz(@ModelAttribute QuizEntity quiz, Model model, @PathVariable String quizId) { + this.quizRepository.save(quiz); + model.addAttribute("quiz", quiz); + model.addAttribute("successMessage", "Quiz successfully saved"); + return QUIZ_EDIT_PAGE; + } +} diff --git a/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizAnswerControllerMVCTest.java b/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizAnswerControllerMVCTest.java new file mode 100644 index 0000000..b712e2d --- /dev/null +++ b/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizAnswerControllerMVCTest.java @@ -0,0 +1,92 @@ +package fr.univ_lille.gitlab.classrooms.quiz; + +import fr.univ_lille.gitlab.classrooms.domain.ClassroomRole; +import fr.univ_lille.gitlab.classrooms.quiz.QuizEntity; +import fr.univ_lille.gitlab.classrooms.quiz.QuizRepository; +import fr.univ_lille.gitlab.classrooms.quiz.QuizScore; +import fr.univ_lille.gitlab.classrooms.quiz.QuizScoreService; +import fr.univ_lille.gitlab.classrooms.ui.WithMockClassroomUser; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.util.Optional; + +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@SpringBootTest +@AutoConfigureMockMvc +class QuizAnswerControllerMVCTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private QuizRepository quizRepository; + + @MockBean + private QuizScoreService quizScoreService; + + @Test + @WithMockClassroomUser(username = "luke.skywalker", roles = {ClassroomRole.STUDENT}) + void shouldReturn404_whenQuizDoesNotExists() throws Exception { + mockMvc.perform(get("/quiz/unknown")) + .andDo(print()) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockClassroomUser(username = "luke.skywalker", roles = {ClassroomRole.STUDENT}) + void shouldReturnQuizPage_whenQuizExists() throws Exception { + var quiz = new QuizEntity(); + quiz.setName("death-star-quiz"); + quiz.setMarkdownContent(""" + # who build the Death Star ? + (x) the Galactic Empire + ( ) Sauron + """); + when(quizRepository.findById("death-star-quiz")).thenReturn(Optional.of(quiz)); + + mockMvc.perform(get("/quiz/death-star-quiz")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(view().name("quiz")) + .andExpect(model().attributeExists("quiz")) + .andExpect(model().attributeDoesNotExist("previousSubmission")); + } + + @Test + @WithMockClassroomUser(username = "luke.skywalker", roles = {ClassroomRole.STUDENT}) + void shouldReturnQuizPage_withPreviouslySubmittedAnswer_whenQuizExists() throws Exception { + var quiz = new QuizEntity(); + quiz.setName("death-star-quiz"); + quiz.setMarkdownContent(""" + # who build the Death Star ? + (x) the Galactic Empire + ( ) Sauron + """); + when(quizRepository.findById("death-star-quiz")).thenReturn(Optional.of(quiz)); + + var quizScore = new QuizScore(); + when(quizScoreService.getPreviousQuizSubmission("death-star-quiz", "luke.skywalker")).thenReturn(Optional.of(quizScore)); + + mockMvc.perform(get("/quiz/death-star-quiz")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(view().name("quiz")) + .andExpect(model().attributeExists("quiz")) + .andExpect(model().attributeExists("previousSubmission")); + } + +} diff --git a/src/test/java/fr/univ_lille/gitlab/classrooms/ui/QuizControllerTest.java b/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizAnswerControllerTest.java similarity index 75% rename from src/test/java/fr/univ_lille/gitlab/classrooms/ui/QuizControllerTest.java rename to src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizAnswerControllerTest.java index 8786e95..b7f1f84 100644 --- a/src/test/java/fr/univ_lille/gitlab/classrooms/ui/QuizControllerTest.java +++ b/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizAnswerControllerTest.java @@ -1,6 +1,10 @@ -package fr.univ_lille.gitlab.classrooms.ui; +package fr.univ_lille.gitlab.classrooms.quiz; -import fr.univ_lille.gitlab.classrooms.quiz.*; +import fr.univ_lille.gitlab.classrooms.quiz.Quiz; +import fr.univ_lille.gitlab.classrooms.quiz.QuizEntity; +import fr.univ_lille.gitlab.classrooms.quiz.QuizRepository; +import fr.univ_lille.gitlab.classrooms.quiz.QuizScoreService; +import fr.univ_lille.gitlab.classrooms.quiz.QuizAnswerController; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -18,10 +22,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -class QuizControllerTest { +class QuizAnswerControllerTest { @InjectMocks - private QuizController quizController; + private QuizAnswerController quizAnswerController; @Mock private QuizRepository quizRepository; @@ -45,7 +49,7 @@ class QuizControllerTest { """); when(quizRepository.findById("testQuiz")).thenReturn(Optional.of(quiz)); - quizController.submitQuizAnswers(model, "testQuiz", Map.of(), authentication); + quizAnswerController.submitQuizAnswers(model, "testQuiz", Map.of(), authentication); verify(model).addAttribute("message", "Il manque des réponses à certaines questions."); } @@ -65,7 +69,7 @@ class QuizControllerTest { // get the answer id from the first answer of the quiz var answerKey = Quiz.fromMarkdown(quiz.getMarkdownContent(), quizId).getQuestions().get(0).getAnswers().get(0).getId(); - var result = quizController.submitQuizAnswers(model, quizId, Map.of(answerKey, "wrong answer"), authentication); + var result = quizAnswerController.submitQuizAnswers(model, quizId, Map.of(answerKey, "wrong answer"), authentication); assertThat(result).isEqualTo("quiz-submitted-with-answers-correction"); diff --git a/src/test/java/fr/univ_lille/gitlab/classrooms/ui/QuizControllerMVCTest.java b/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizEditionControllerMVCTest.java similarity index 79% rename from src/test/java/fr/univ_lille/gitlab/classrooms/ui/QuizControllerMVCTest.java rename to src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizEditionControllerMVCTest.java index fc82ba3..b42f9fa 100644 --- a/src/test/java/fr/univ_lille/gitlab/classrooms/ui/QuizControllerMVCTest.java +++ b/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizEditionControllerMVCTest.java @@ -1,8 +1,9 @@ -package fr.univ_lille.gitlab.classrooms.ui; +package fr.univ_lille.gitlab.classrooms.quiz; import fr.univ_lille.gitlab.classrooms.domain.ClassroomRole; import fr.univ_lille.gitlab.classrooms.quiz.QuizEntity; import fr.univ_lille.gitlab.classrooms.quiz.QuizRepository; +import fr.univ_lille.gitlab.classrooms.ui.WithMockClassroomUser; import org.hamcrest.Matcher; import org.hamcrest.Matchers; import org.junit.jupiter.api.Nested; @@ -26,7 +27,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @SpringBootTest @AutoConfigureMockMvc -class QuizControllerMVCTest { +class QuizEditionControllerMVCTest { @Autowired private MockMvc mockMvc; @@ -123,31 +124,4 @@ class QuizControllerMVCTest { } - @Test - @WithMockClassroomUser(username = "luke.skywalker", roles = {ClassroomRole.STUDENT}) - void shouldReturn404_whenQuizDoesNotExists() throws Exception { - mockMvc.perform(get("/quiz/unknown")) - .andDo(print()) - .andExpect(status().isNotFound()); - } - - @Test - @WithMockClassroomUser(username = "luke.skywalker", roles = {ClassroomRole.STUDENT}) - void shouldReturnQuizPage_whenQuizExists() throws Exception { - var quiz = new QuizEntity(); - quiz.setName("death-star-quiz"); - quiz.setMarkdownContent(""" - # who build the Death Star ? - (x) the Galactic Empire - ( ) Sauron - """); - when(quizRepository.findById("death-star-quiz")).thenReturn(Optional.of(quiz)); - - mockMvc.perform(get("/quiz/death-star-quiz")) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(view().name("quiz")) - .andExpect(model().attribute("quiz", notNullValue())); - } - } diff --git a/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizScoreServiceImplTest.java b/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizScoreServiceImplTest.java index 9d7888f..3d529e9 100644 --- a/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizScoreServiceImplTest.java +++ b/src/test/java/fr/univ_lille/gitlab/classrooms/quiz/QuizScoreServiceImplTest.java @@ -46,10 +46,10 @@ class QuizScoreServiceImplTest { var quizScore = captor.getValue(); assertThat(quizScore.quizId).isEqualTo("dummy"); - assertThat(quizScore.score).isEqualTo(0); + assertThat(quizScore.score).isZero(); assertThat(quizScore.studentId).isEqualTo("darth-vader"); - assertThat(quizScore.submissionCount).isEqualTo(1); - assertThat(quizScore.maxScore).isEqualTo(1); + assertThat(quizScore.submissionCount).isOne(); + assertThat(quizScore.maxScore).isOne(); assertThat(quizScore.submissionDate).isEqualToIgnoringSeconds(ZonedDateTime.now()); } -} \ No newline at end of file +}