1 package fr.tiogars.chat.domains.settings.user.controllers;
2
3 import static org.mockito.ArgumentMatchers.any;
4 import static org.mockito.ArgumentMatchers.eq;
5 import static org.mockito.Mockito.never;
6 import static org.mockito.Mockito.verify;
7 import static org.mockito.Mockito.when;
8 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
9 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
10 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
11 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
12
13 import java.security.Principal;
14 import java.time.Instant;
15 import java.util.Optional;
16
17 import org.junit.jupiter.api.Test;
18 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
20 import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
21 import org.springframework.context.annotation.Import;
22 import org.springframework.http.MediaType;
23 import org.springframework.security.core.userdetails.UserDetailsService;
24 import org.springframework.test.context.bean.override.mockito.MockitoBean;
25 import org.springframework.test.web.servlet.MockMvc;
26
27 import fr.tiogars.chat.config.ApiCorsConfiguration;
28 import fr.tiogars.chat.domains.auth.services.JwtTokenService;
29 import fr.tiogars.chat.domains.settings.user.entities.UserSettings;
30 import fr.tiogars.chat.domains.settings.user.models.UpdateUserSettingsRequest;
31 import fr.tiogars.chat.domains.settings.user.services.UserSettingsService;
32
33 @WebMvcTest({
34 MyUserSettingsReadController.class,
35 MyUserSettingsUpdateController.class,
36 UserSettingsReadController.class,
37 UserSettingsUpdateController.class,
38 AnonymousUserSettingsReadController.class,
39 AnonymousUserSettingsUpdateController.class
40 })
41 @AutoConfigureMockMvc(addFilters = false)
42 @Import(ApiCorsConfiguration.class)
43 class UserSettingsControllerTest {
44
45 private static final Instant TIMESTAMP = Instant.parse("2026-01-02T03:04:05Z");
46 private static final Principal ALICE = () -> "alice";
47
48 @Autowired
49 private MockMvc mockMvc;
50
51 @MockitoBean
52 private UserSettingsService service;
53
54 @MockitoBean
55 private JwtTokenService jwtTokenService;
56
57 @MockitoBean
58 private UserDetailsService userDetailsService;
59
60 @Test
61 void readMine_returnsSettingsOfAuthenticatedAccount() throws Exception {
62 when(service.findByUsername("alice")).thenReturn(Optional.of(settings(7L, null, "dark")));
63
64 mockMvc.perform(get("/api/v1/settings/user/me").principal(ALICE))
65 .andExpect(status().isOk())
66 .andExpect(jsonPath("$.userId").value(7))
67 .andExpect(jsonPath("$.viewMode").value("dark"));
68 }
69
70 @Test
71 void updateMine_updatesSettingsOfAuthenticatedAccount() throws Exception {
72 when(service.updateByUsername(eq("alice"), any(UpdateUserSettingsRequest.class)))
73 .thenReturn(Optional.of(settings(7L, null, "light")));
74
75 mockMvc.perform(put("/api/v1/settings/user/me")
76 .principal(ALICE)
77 .contentType(MediaType.APPLICATION_JSON)
78 .content("{\"viewMode\":\"light\"}"))
79 .andExpect(status().isOk())
80 .andExpect(jsonPath("$.viewMode").value("light"));
81 }
82
83 @Test
84 void updateMine_rejectsUnknownViewMode() throws Exception {
85 mockMvc.perform(put("/api/v1/settings/user/me")
86 .principal(ALICE)
87 .contentType(MediaType.APPLICATION_JSON)
88 .content("{\"viewMode\":\"neon\"}"))
89 .andExpect(status().isBadRequest());
90
91 verify(service, never()).updateByUsername(any(), any());
92 }
93
94 @Test
95 void readUser_returnsNotFoundWhenAccountIsNotManaged() throws Exception {
96 when(service.findByUserId(1L)).thenReturn(Optional.empty());
97
98 mockMvc.perform(get("/api/v1/settings/user/users/1"))
99 .andExpect(status().isNotFound());
100 }
101
102 @Test
103 void updateUser_updatesSettingsOfUserRoleAccount() throws Exception {
104 when(service.updateByUserId(eq(9L), any(UpdateUserSettingsRequest.class)))
105 .thenReturn(Optional.of(settings(9L, null, "dark")));
106
107 mockMvc.perform(put("/api/v1/settings/user/users/9")
108 .contentType(MediaType.APPLICATION_JSON)
109 .content("{\"viewMode\":\"dark\"}"))
110 .andExpect(status().isOk())
111 .andExpect(jsonPath("$.userId").value(9))
112 .andExpect(jsonPath("$.viewMode").value("dark"));
113 }
114
115 @Test
116 void readAnonymous_returnsRoleSettings() throws Exception {
117 when(service.findAnonymous()).thenReturn(settings(null, "ANONYMOUS", "system"));
118
119 mockMvc.perform(get("/api/v1/settings/user/anonymous"))
120 .andExpect(status().isOk())
121 .andExpect(jsonPath("$.roleCode").value("ANONYMOUS"))
122 .andExpect(jsonPath("$.viewMode").value("system"));
123 }
124
125 @Test
126 void updateAnonymous_updatesRoleSettings() throws Exception {
127 when(service.updateAnonymous(any(UpdateUserSettingsRequest.class)))
128 .thenReturn(settings(null, "ANONYMOUS", "dark"));
129
130 mockMvc.perform(put("/api/v1/settings/user/anonymous")
131 .contentType(MediaType.APPLICATION_JSON)
132 .content("{\"viewMode\":\"dark\"}"))
133 .andExpect(status().isOk())
134 .andExpect(jsonPath("$.viewMode").value("dark"));
135 }
136
137 private static UserSettings settings(Long userId, String roleCode, String viewMode) {
138 return new UserSettings(userId, roleCode, viewMode, TIMESTAMP, TIMESTAMP);
139 }
140 }