package com.mosquito.project.dto; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Nested; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * CreateApiKeyResponse DTO测试 */ @DisplayName("CreateApiKeyResponse DTO测试") class CreateApiKeyResponseTest { private ObjectMapper objectMapper; @BeforeEach void setUp() { objectMapper = new ObjectMapper(); } @Nested @DisplayName("构造函数测试") class ConstructorTests { @Test @DisplayName("全参数构造函数应该正确设置apiKey字段") void shouldSetApiKeyCorrectly_WhenUsingAllArgsConstructor() { // Given String apiKey = "test-api-key-12345"; // When CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey); // Then assertThat(response.getApiKey()).isEqualTo(apiKey); } @Test @DisplayName("null值构造函数应该正确处理") void shouldHandleNull_WhenUsingConstructor() { // When CreateApiKeyResponse response = new CreateApiKeyResponse(null); // Then assertThat(response.getApiKey()).isNull(); } @Test @DisplayName("空字符串构造函数应该正确处理") void shouldHandleEmptyString_WhenUsingConstructor() { // When CreateApiKeyResponse response = new CreateApiKeyResponse(""); // Then assertThat(response.getApiKey()).isEmpty(); } @Test @DisplayName("空白字符串构造函数应该正确处理") void shouldHandleWhitespace_WhenUsingConstructor() { // Given String whitespaceKey = " "; // When CreateApiKeyResponse response = new CreateApiKeyResponse(whitespaceKey); // Then assertThat(response.getApiKey()).isEqualTo(whitespaceKey); } @Test @DisplayName("长字符串构造函数应该正确处理") void shouldHandleLongString_WhenUsingConstructor() { // Given StringBuilder longKey = new StringBuilder(); for (int i = 0; i < 1000; i++) { longKey.append("key").append(i); } String longApiKey = longKey.toString(); // When CreateApiKeyResponse response = new CreateApiKeyResponse(longApiKey); // Then assertThat(response.getApiKey()).isEqualTo(longApiKey); assertThat(response.getApiKey()).hasSizeGreaterThan(2000); } @Test @DisplayName("特殊字符apiKey构造函数应该正确处理") void shouldHandleSpecialCharacters_WhenUsingConstructor() { // Given String specialKey = "key-🔑-测试!@#$%^&*()_+-=[]{}|;':\",./<>?"; // When CreateApiKeyResponse response = new CreateApiKeyResponse(specialKey); // Then assertThat(response.getApiKey()).isEqualTo(specialKey); } @Test @DisplayName("包含换行符apiKey构造函数应该正确处理") void shouldHandleNewlines_WhenUsingConstructor() { // Given String keyWithNewlines = "line1\nline2\r\nline3\t"; // When CreateApiKeyResponse response = new CreateApiKeyResponse(keyWithNewlines); // Then assertThat(response.getApiKey()).isEqualTo(keyWithNewlines); } } @Nested @DisplayName("Getter测试") class GetterTests { @Test @DisplayName("getApiKey应该返回正确的值") void shouldReturnCorrectValue_WhenUsingGetter() { // Given String apiKey = "my-secret-api-key"; CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey); // When String result = response.getApiKey(); // Then assertThat(result).isEqualTo(apiKey); } @Test @DisplayName("getApiKey应该返回null当值为null") void shouldReturnNull_WhenValueIsNull() { // Given CreateApiKeyResponse response = new CreateApiKeyResponse(null); // When String result = response.getApiKey(); // Then assertThat(result).isNull(); } @Test @DisplayName("getApiKey应该返回空字符串当值为空") void shouldReturnEmptyString_WhenValueIsEmpty() { // Given CreateApiKeyResponse response = new CreateApiKeyResponse(""); // When String result = response.getApiKey(); // Then assertThat(result).isEmpty(); } } @Nested @DisplayName("边界值测试") class BoundaryTests { @ParameterizedTest @NullAndEmptySource @ValueSource(strings = {" ", "\t", "\n", "\r"}) @DisplayName("边界值apiKey应该正确处理") void shouldHandleBoundaryValues(String apiKey) { // When CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey); // Then assertThat(response.getApiKey()).isEqualTo(apiKey); } @ParameterizedTest @ValueSource(strings = { "a", // 单字符 "AB", // 双字符 "0123456789", // 数字 "abcdefghijklmnopqrstuvwxyz", // 小写字母 "ABCDEFGHIJKLMNOPQRSTUVWXYZ", // 大写字母 "key-with-dashes", // 带横线 "key_with_underscores", // 带下划线 "key.with.dots", // 带点 "key:with:colons", // 带冒号 "key/with/slashes" // 带斜杠 }) @DisplayName("各种格式apiKey应该正确处理") void shouldHandleVariousFormats(String apiKey) { // When CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey); // Then assertThat(response.getApiKey()).isEqualTo(apiKey); } @Test @DisplayName("Unicode字符apiKey应该正确处理") void shouldHandleUnicodeCharacters() { // Given String[] unicodeKeys = { "密钥-中文测试", "ключ-русский", "キー-日本語", "🔑-emoji-test", "مفتاح-عربي" }; for (String key : unicodeKeys) { // When CreateApiKeyResponse response = new CreateApiKeyResponse(key); // Then assertThat(response.getApiKey()).isEqualTo(key); } } @Test @DisplayName("极大长度apiKey应该正确处理") void shouldHandleExtremelyLongKey() { // Given StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) { sb.append("A"); } String extremelyLongKey = sb.toString(); // When CreateApiKeyResponse response = new CreateApiKeyResponse(extremelyLongKey); // Then assertThat(response.getApiKey()).hasSize(10000); assertThat(response.getApiKey()).isEqualTo(extremelyLongKey); } @Test @DisplayName("JSON特殊字符apiKey应该正确处理") void shouldHandleJsonSpecialCharacters() { // Given String jsonSpecialKey = "key{with}[brackets]\"quotes\"'apostrophe'"; // When CreateApiKeyResponse response = new CreateApiKeyResponse(jsonSpecialKey); // Then assertThat(response.getApiKey()).isEqualTo(jsonSpecialKey); } } @Nested @DisplayName("JSON序列化测试") class JsonSerializationTests { @Test @DisplayName("完整对象应该正确序列化为JSON") void shouldSerializeCorrectly_CompleteObject() throws JsonProcessingException { // Given String apiKey = "test-api-key-12345"; CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey); // When String json = objectMapper.writeValueAsString(response); // Then assertThat(json).isNotNull(); assertThat(json).contains("\"apiKey\":\"test-api-key-12345\""); } @Test @DisplayName("null值应该正确序列化为JSON") void shouldSerializeCorrectly_WithNullValue() throws JsonProcessingException { // Given CreateApiKeyResponse response = new CreateApiKeyResponse(null); // When String json = objectMapper.writeValueAsString(response); // Then assertThat(json).isNotNull(); assertThat(json).contains("\"apiKey\":null"); } @Test @DisplayName("空字符串应该正确序列化为JSON") void shouldSerializeCorrectly_WithEmptyString() throws JsonProcessingException { // Given CreateApiKeyResponse response = new CreateApiKeyResponse(""); // When String json = objectMapper.writeValueAsString(response); // Then assertThat(json).contains("\"apiKey\":\"\""); } @Test @DisplayName("特殊字符应该正确序列化为JSON") void shouldSerializeCorrectly_WithSpecialCharacters() throws JsonProcessingException { // Given String specialKey = "key-🔑-测试"; CreateApiKeyResponse response = new CreateApiKeyResponse(specialKey); // When String json = objectMapper.writeValueAsString(response); // Then assertThat(json).isNotNull(); assertThat(json).contains("apiKey"); } @Test @DisplayName("JSON转义字符应该正确序列化") void shouldSerializeCorrectly_WithJsonEscapes() throws JsonProcessingException { // Given String keyWithEscapes = "line1\nline2\t\"quoted\""; CreateApiKeyResponse response = new CreateApiKeyResponse(keyWithEscapes); // When String json = objectMapper.writeValueAsString(response); // Then assertThat(json).isNotNull(); assertThat(json).contains("apiKey"); } } @Nested @DisplayName("对象行为测试") class ObjectBehaviorTests { @Test @DisplayName("两个相同apiKey的响应应该相等") void shouldBeEqual_WhenSameApiKey() { // Given CreateApiKeyResponse response1 = new CreateApiKeyResponse("same-key"); CreateApiKeyResponse response2 = new CreateApiKeyResponse("same-key"); // Then assertThat(response1.getApiKey()).isEqualTo(response2.getApiKey()); } @Test @DisplayName("两个不同apiKey的响应应该不相等") void shouldNotBeEqual_WhenDifferentApiKey() { // Given CreateApiKeyResponse response1 = new CreateApiKeyResponse("key-1"); CreateApiKeyResponse response2 = new CreateApiKeyResponse("key-2"); // Then assertThat(response1.getApiKey()).isNotEqualTo(response2.getApiKey()); } @Test @DisplayName("多次调用getter应该返回相同值") void shouldReturnSameValue_WhenCallingGetterMultipleTimes() { // Given String apiKey = "consistent-key"; CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey); // When & Then assertThat(response.getApiKey()).isEqualTo(apiKey); assertThat(response.getApiKey()).isEqualTo(apiKey); assertThat(response.getApiKey()).isEqualTo(apiKey); } } @Nested @DisplayName("并发安全测试") class ConcurrencyTests { @Test @DisplayName("多线程并发读取应该是安全的") void shouldBeThreadSafe_ConcurrentReads() throws InterruptedException { // Given String apiKey = "concurrent-key"; CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey); int threadCount = 10; Thread[] threads = new Thread[threadCount]; boolean[] results = new boolean[threadCount]; // When for (int i = 0; i < threadCount; i++) { final int threadIndex = i; threads[i] = new Thread(() -> { try { for (int j = 0; j < 100; j++) { String value = response.getApiKey(); if (!apiKey.equals(value)) { results[threadIndex] = false; return; } } results[threadIndex] = true; } catch (Exception e) { results[threadIndex] = false; } }); } // 启动所有线程 for (Thread thread : threads) { thread.start(); } // 等待所有线程完成 for (Thread thread : threads) { thread.join(); } // Then for (int i = 0; i < threadCount; i++) { assertThat(results[i]).isTrue(); } } } }