post_rating

Change-Id: Ia1a6fb3f87b793a6307046e36951c1fb36b213c8
diff --git a/src/test/java/com/example/g8backend/service/ForgotPasswordServiceImplTest.java b/src/test/java/com/example/g8backend/service/ForgotPasswordServiceImplTest.java
new file mode 100644
index 0000000..05535fd
--- /dev/null
+++ b/src/test/java/com/example/g8backend/service/ForgotPasswordServiceImplTest.java
@@ -0,0 +1,77 @@
+package com.example.g8backend.service;
+
+import com.example.g8backend.entity.User;
+import com.example.g8backend.mapper.UserMapper;
+import com.example.g8backend.service.impl.ForgotPasswordServiceImpl;
+import com.example.g8backend.util.mailUtil; // Import mailUtil
+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.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+public class ForgotPasswordServiceImplTest {
+
+    @Mock
+    private UserMapper userMapper;
+    @Mock
+    private RedisTemplate<String, String> redisTemplate;
+    @Mock
+    private PasswordEncoder passwordEncoder;
+    @Mock
+    private mailUtil mailUtil;  // Mock mailUtil
+
+    @InjectMocks
+    private ForgotPasswordServiceImpl forgotPasswordService;
+
+    @Mock
+    private ValueOperations<String, String> valueOperations; // Mock Redis ValueOperations
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+        when(redisTemplate.opsForValue()).thenReturn(valueOperations); // Mock Redis operations
+    }
+
+    @Test
+    void sendCodeToEmail_Success() {
+        User user = new User();
+        user.setUserName("test");
+        user.setEmail("test@example.com");
+        when(userMapper.getUserByName("test")).thenReturn(user);
+
+        // Call the method under test
+        forgotPasswordService.sendCodeToEmail("test");
+
+        // Verify that mailUtil.sendMail was called once with the expected arguments
+        verify(mailUtil, times(1)).sendMail(eq("test@example.com"), eq("重置密码验证码"), contains("您的验证码"));
+        verify(redisTemplate, times(1)).opsForValue();
+    }
+
+    @Test
+    void resetPassword_Success() {
+        User user = new User();
+        user.setUserName("test");
+        user.setPassword("old");
+        when(userMapper.getUserByName("test")).thenReturn(user);
+        when(redisTemplate.opsForValue().get("reset_code:test")).thenReturn("123456");
+        when(passwordEncoder.encode("newpass")).thenReturn("encodedNew");
+        when(userMapper.updateById(any(User.class))).thenReturn(1);
+
+        boolean result = forgotPasswordService.resetPassword("test", "123456", "newpass");
+        assertTrue(result);
+        verify(redisTemplate, times(1)).delete("reset_code:test");
+    }
+
+    @Test
+    void resetPassword_WrongCode() {
+        when(redisTemplate.opsForValue().get("reset_code:test")).thenReturn("654321");
+        assertThrows(RuntimeException.class, () -> forgotPasswordService.resetPassword("test", "123456", "newpass"));
+    }
+}
diff --git a/src/test/java/com/example/g8backend/service/PostRatingServiceImplTest.java b/src/test/java/com/example/g8backend/service/PostRatingServiceImplTest.java
new file mode 100644
index 0000000..942080a
--- /dev/null
+++ b/src/test/java/com/example/g8backend/service/PostRatingServiceImplTest.java
@@ -0,0 +1,103 @@
+package com.example.g8backend.service;
+
+import com.example.g8backend.entity.PostRating;
+import com.example.g8backend.mapper.PostMapper;
+import com.example.g8backend.mapper.PostRatingMapper;
+import com.example.g8backend.service.impl.PostRatingServiceImpl;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.transaction.annotation.Transactional;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+@Transactional
+public class PostRatingServiceImplTest {
+
+    @Mock
+    private PostRatingMapper postRatingMapper;
+
+    @Mock
+    private PostMapper postMapper;
+
+    @InjectMocks
+    private PostRatingServiceImpl postRatingService;
+
+    private final Long userId = 1L;
+    private final Long postId = 100L;
+    private final Integer validRating = 4;
+    private final Integer invalidRating = 6;
+
+    // 测试:合法评分应成功
+    @Test
+    public void testRatePost_Success() {
+        // 模拟依赖行为
+        when(postRatingMapper.insertOrUpdate(any(PostRating.class))).thenReturn(true);
+        when(postRatingMapper.calculateAverageRating(postId)).thenReturn(4.0);
+        when(postRatingMapper.getRatingCount(postId)).thenReturn(1);
+
+        // 调用方法并验证无异常
+        assertDoesNotThrow(() -> {
+            postRatingService.ratePost(userId, postId, validRating);
+        });
+
+        // 验证数据库交互
+        verify(postMapper).updateRatingStats(eq(postId), eq(4.0), eq(1));
+    }
+
+    // 测试:非法评分应抛出异常
+    @Test
+    public void testRatePost_InvalidRating() {
+        // 调用方法并验证异常
+        IllegalArgumentException exception = assertThrows(
+                IllegalArgumentException.class,
+                () -> postRatingService.ratePost(userId, postId, invalidRating)
+        );
+        assertEquals("评分值必须在1到5之间", exception.getMessage());
+
+        // 验证未调用数据库操作
+        verifyNoInteractions(postRatingMapper);
+    }
+
+    // 测试:重复评分应更新记录
+    @Test
+    public void testRatePost_UpdateExistingRating() {
+        // 模拟已存在评分
+        when(postRatingMapper.insertOrUpdate(any(PostRating.class))).thenReturn(true);
+        when(postRatingMapper.calculateAverageRating(postId)).thenReturn(3.5, 4.0); // 两次调用返回不同值
+        when(postRatingMapper.getRatingCount(postId)).thenReturn(1);
+
+        // 同一用户对同一帖子二次评分
+        assertDoesNotThrow(() -> {
+            postRatingService.ratePost(userId, postId, 3);
+            postRatingService.ratePost(userId, postId, 4);
+        });
+
+        // 验证两次更新统计信息
+        verify(postMapper, times(2)).updateRatingStats(eq(postId), anyDouble(), eq(1));
+    }
+
+    // 测试:数据库操作失败应抛出异常
+    @Test
+    public void testRatePost_DatabaseFailure() {
+        when(postRatingMapper.insertOrUpdate(any(PostRating.class))).thenReturn(false);
+        RuntimeException exception = assertThrows(
+                RuntimeException.class,
+                () -> postRatingService.ratePost(userId, postId, validRating)
+        );
+        assertEquals("评分操作失败", exception.getMessage());
+    }
+    // 测试:获取评分用户数量
+    @Test
+    public void testGetRatingUserCount() {
+        when(postRatingMapper.selectRatingUserCount(postId)).thenReturn(5L);
+        Long count = postRatingService.getRatingUserCount(postId);
+        assertEquals(5L, count);
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/example/g8backend/service/TorrentServiceTest.java b/src/test/java/com/example/g8backend/service/TorrentServiceTest.java
index 6ddca58..fd6d88a 100644
--- a/src/test/java/com/example/g8backend/service/TorrentServiceTest.java
+++ b/src/test/java/com/example/g8backend/service/TorrentServiceTest.java
@@ -83,12 +83,13 @@
                     .thenReturn(mockedBytes);
             mockedStatic.when(() -> TorrentUtil.getInfoHash(any(File.class)))
                     .thenReturn(expectedInfoHash);
-            Torrent torrent = torrentService.handleTorrentUpload(torrentFile, userId, passkey);
+            Torrent torrent = torrentService.handleTorrentUpload(torrentFile,"test.torrent", userId, passkey);
 
             // 验证调用
             verify(torrentMapper, times(1))
                     .insertTorrent(eq(1L),
                             anyString(),
+                            anyString(),
                             eq("modified-info-hash"),
                             eq(torrentFile.length()/1024.0/1024.0));
 
diff --git a/src/test/java/com/example/g8backend/service/TrackerServiceTest.java b/src/test/java/com/example/g8backend/service/TrackerServiceTest.java
index 829fe15..e2bd4c9 100644
--- a/src/test/java/com/example/g8backend/service/TrackerServiceTest.java
+++ b/src/test/java/com/example/g8backend/service/TrackerServiceTest.java
@@ -4,12 +4,14 @@
 import com.example.g8backend.dto.AnnounceResponseDTO;
 import com.example.g8backend.entity.Peer;
 import com.example.g8backend.mapper.PeerMapper;
+import com.example.g8backend.mapper.UserStatsMapper;
 import com.example.g8backend.service.impl.TrackerServiceImpl;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.*;
 import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.data.redis.core.HashOperations;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.SetOperations;
 
@@ -29,9 +31,15 @@
     private PeerMapper peerMapper;
 
     @Mock
+    private UserStatsMapper userStatsMapper;
+
+    @Mock
     private RedisTemplate<String, Object> redisTemplate;
 
     @Mock
+    private HashOperations<String, Object, Object> hashOperations;
+
+    @Mock
     private SetOperations<String, Object> setOperations;
 
     @BeforeEach
@@ -100,12 +108,19 @@
         existing.setUploaded(1000.0);
         existing.setDownloaded(500.0);
 
+        Map<Object, Object> redisData = new HashMap<>();
+        redisData.put("uploaded", 1000.0);
+        redisData.put("downloaded", 500.0);
+
         when(peerMapper.getPeerByPK("peer2", "infohash", "key123")).thenReturn(existing);
-        when(setOperations.members("peers:infohash")).thenReturn(Set.of("peer2"));
         when(peerMapper.getPeerByInfoHashAndPeerId("infohash", "peer2")).thenReturn(List.of(new Peer() {{
             setIpAddress("192.168.1.1");
             setPort(6882);
         }}));
+        when(redisTemplate.opsForHash()).thenReturn(hashOperations);
+        when(hashOperations.entries("user:peer:key123:infohash:peer2")).thenReturn(redisData);
+        when(redisTemplate.opsForSet()).thenReturn(setOperations);
+        when(setOperations.members("peers:infohash")).thenReturn(Set.of("peer2"));
 
         AnnounceResponseDTO response = trackerService.handleAnnounce(requestDTO);
 
diff --git a/src/test/java/com/example/g8backend/service/UserSecurityServiceImplTest.java b/src/test/java/com/example/g8backend/service/UserSecurityServiceImplTest.java
new file mode 100644
index 0000000..f04fbc5
--- /dev/null
+++ b/src/test/java/com/example/g8backend/service/UserSecurityServiceImplTest.java
@@ -0,0 +1,55 @@
+package com.example.g8backend.service;
+
+import com.example.g8backend.entity.User;
+import com.example.g8backend.mapper.UserMapper;
+import com.example.g8backend.service.impl.UserSecurityServiceImpl;
+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.security.crypto.password.PasswordEncoder;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+public class UserSecurityServiceImplTest {
+
+    @Mock
+    private UserMapper userMapper;
+    @Mock
+    private PasswordEncoder passwordEncoder;
+
+    @InjectMocks
+    private UserSecurityServiceImpl userSecurityService;
+
+    private User user;
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+        user = new User();
+        user.setUserId(1L);
+        user.setPassword("encodedOld");
+    }
+
+    @Test
+    void changePassword_Success() {
+        when(userMapper.selectById(1L)).thenReturn(user);
+        when(passwordEncoder.matches("old", "encodedOld")).thenReturn(true);
+        when(passwordEncoder.encode("new")).thenReturn("encodedNew");
+        when(userMapper.updateById(any(User.class))).thenReturn(1);
+
+        boolean result = userSecurityService.changePassword(1L, "old", "new");
+        assertTrue(result);
+        verify(userMapper).updateById(any(User.class));
+    }
+
+    @Test
+    void changePassword_WrongOldPassword() {
+        when(userMapper.selectById(1L)).thenReturn(user);
+        when(passwordEncoder.matches("wrong", "encodedOld")).thenReturn(false);
+
+        assertThrows(RuntimeException.class, () -> userSecurityService.changePassword(1L, "wrong", "new"));
+    }
+}
\ No newline at end of file