diff --git a/.env.example b/.env.example
index 044c869d4..9a5f2670f 100755
--- a/.env.example
+++ b/.env.example
@@ -1,25 +1,6 @@
VOLCENGINE_TOS_ACCESS_KEY=
VOLCENGINE_TOS_SECRET_KEY=
-# MinIO Configuration
-MINIO_USER=
-MINIO_PASSWORD=
-MINIO_PORT=
-
-# Global Domain Configuration
-GLOBAL_DOMAIN=
-GLOBAL_IP=
-
-# Database Configuration
-PG_USER=
-PG_PASSWORD=
-PG_DB=
-PG_PORT=
-
-# Redis Configuration
-REDIS_PASSWORD=
-REDIS_PORT=
-
# WeChat Configuration (placeholders)
WXPA_VERIFY_TOKEN=
WXPA_APP_ID=
diff --git a/.idea/modules/compose-server.iml b/.idea/modules/compose-server.iml
index b8ff23d5c..331ff96a1 100644
--- a/.idea/modules/compose-server.iml
+++ b/.idea/modules/compose-server.iml
@@ -14,6 +14,7 @@
+
\ No newline at end of file
diff --git a/cacheable/build.gradle.kts b/cacheable/build.gradle.kts
index aec450a5a..88f559274 100644
--- a/cacheable/build.gradle.kts
+++ b/cacheable/build.gradle.kts
@@ -11,7 +11,7 @@ Includes Redis integration for distributed caching and Caffeine for high-perform
.trimIndent()
dependencies {
- implementation(libs.org.springframework.boot.spring.boot.starter.data.redis)
+ api(libs.org.springframework.boot.spring.boot.starter.data.redis)
implementation(libs.org.apache.commons.commons.pool2)
implementation(libs.com.github.ben.manes.caffeine.caffeine)
diff --git a/cacheable/src/main/kotlin/io/github/truenine/composeserver/cacheable/autoconfig/RedisJsonSerializerAutoConfiguration.kt b/cacheable/src/main/kotlin/io/github/truenine/composeserver/cacheable/autoconfig/RedisJsonSerializerAutoConfiguration.kt
index 18c1c956d..d826caf9b 100644
--- a/cacheable/src/main/kotlin/io/github/truenine/composeserver/cacheable/autoconfig/RedisJsonSerializerAutoConfiguration.kt
+++ b/cacheable/src/main/kotlin/io/github/truenine/composeserver/cacheable/autoconfig/RedisJsonSerializerAutoConfiguration.kt
@@ -43,7 +43,6 @@ class RedisJsonSerializerAutoConfiguration(@Qualifier(JacksonAutoConfiguration.N
.disableCachingNullValues()
@Bean(name = [ICacheNames.IRedis.HANDLE])
- @ConditionalOnBean(name = [VIRTUAL_THREAD_REDIS_FACTORY_BEAN_NAME])
fun customRedisJsonSerializable(@Qualifier(VIRTUAL_THREAD_REDIS_FACTORY_BEAN_NAME) factory: RedisConnectionFactory): RedisTemplate {
log.trace("register redisTemplate factory: {}", factory)
val rt = RedisTemplate()
@@ -58,7 +57,6 @@ class RedisJsonSerializerAutoConfiguration(@Qualifier(JacksonAutoConfiguration.N
}
@Bean(name = [ICacheNames.IRedis.CACHE_MANAGER])
- @ConditionalOnBean(name = [VIRTUAL_THREAD_REDIS_FACTORY_BEAN_NAME])
fun cacheManager2h(@Qualifier(VIRTUAL_THREAD_REDIS_FACTORY_BEAN_NAME) factory: RedisConnectionFactory): RedisCacheManager {
log.debug("register RedisCacheManager , factory: {}", factory)
return asCacheConfig(factory)
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 741138d99..5dee51b55 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -54,7 +54,7 @@ org-springframework-modulith = "2.0.0-M1"
org-springframework-security = "6.5.5"
org-testcontainers = "1.21.3"
org-testng = "7.11.0"
-project = "0.0.37"
+project = "0.0.38"
[libraries]
ch-qos-logback-logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "ch-qos-logback" }
diff --git a/oss/oss-volcengine-tos/.env.example b/oss/oss-volcengine-tos/.env.example
deleted file mode 100644
index addc616d5..000000000
--- a/oss/oss-volcengine-tos/.env.example
+++ /dev/null
@@ -1,13 +0,0 @@
-# Volcengine TOS 环境变量配置示例
-# 复制此文件为 .env 并填入真实的配置值
-
-# Volcengine TOS Access Key ID
-VOLCENGINE_TOS_ACCESS_KEY=your_access_key_here
-
-# Volcengine TOS Secret Access Key
-VOLCENGINE_TOS_SECRET_KEY=your_secret_key_here
-
-# 注意:
-# 1. 请勿将包含真实密钥的 .env 文件提交到版本控制系统
-# 2. 确保 .env 文件已添加到 .gitignore 中
-# 3. 在生产环境中使用更安全的密钥管理方案
diff --git a/oss/oss-volcengine-tos/build.gradle.kts b/oss/oss-volcengine-tos/build.gradle.kts
index e60fe0c5f..8fcaadef9 100644
--- a/oss/oss-volcengine-tos/build.gradle.kts
+++ b/oss/oss-volcengine-tos/build.gradle.kts
@@ -1,37 +1,9 @@
plugins {
id("buildlogic.kotlinspring-conventions")
id("buildlogic.spotless-conventions")
+ id("buildlogic.loadenv-conventions")
}
-// 直接实现 dotenv 功能,避免插件依赖
-fun loadDotenv() {
- val envFile = rootProject.file(".env")
- if (envFile.exists()) {
- envFile.readLines().forEach { line ->
- val trimmedLine = line.trim()
- if (trimmedLine.isNotEmpty() && !trimmedLine.startsWith("#")) {
- val parts = trimmedLine.split("=", limit = 2)
- if (parts.size == 2) {
- val key = parts[0].trim()
- val value = parts[1].trim().removeSurrounding("\"").removeSurrounding("'")
- if (key.isNotEmpty() && value.isNotEmpty()) {
- // 设置到所有任务的环境变量中
- tasks.withType { environment(key, value) }
- tasks.withType { environment(key, value) }
- logger.debug("Loaded environment variable: $key")
- }
- }
- }
- }
- logger.info("Loaded .env file from: ${envFile.absolutePath}")
- } else {
- logger.warn(".env file not found at: ${envFile.absolutePath}")
- }
-}
-
-// 加载 dotenv 配置
-loadDotenv()
-
description =
"""
Volcengine TOS (Tinder Object Storage) integration for enterprise-grade cloud storage.
diff --git a/shared/src/main/kotlin/io/github/truenine/composeserver/AliasExtensions.kt b/shared/src/main/kotlin/io/github/truenine/composeserver/AliasExtensions.kt
index f349e8132..831860032 100644
--- a/shared/src/main/kotlin/io/github/truenine/composeserver/AliasExtensions.kt
+++ b/shared/src/main/kotlin/io/github/truenine/composeserver/AliasExtensions.kt
@@ -21,12 +21,29 @@ inline fun String.isId(): Boolean {
return this.isNotEmpty() && this.matches(Regex("^[0-9A-Za-z]+$"))
}
-@Deprecated("框架内部调用代码,不应由用户直接调用", level = DeprecationLevel.ERROR) inline fun getDefaultNullableId(): Id = Long.MIN_VALUE
+@Deprecated("框架内部调用代码,不应由用户直接调用", level = DeprecationLevel.ERROR)
+inline fun getDefaultNullableId(): Id = Long.MIN_VALUE
inline fun Number.toId(): Id? {
return this.toLong().takeIf { it != Long.MIN_VALUE }
}
+inline fun Number.toId(receiver: (Id) -> T?): T? {
+ return this.toId()?.let(receiver)
+}
+
+inline fun Number.toIdOrThrow(): Id {
+ return this.toLong().takeIf { it != Long.MIN_VALUE } ?: throw IllegalArgumentException("Invalid Id: $this")
+}
+
inline fun String.toId(): Id? {
return this.toLongOrNull()?.takeIf { it != Long.MIN_VALUE }
}
+
+inline fun String.toIdOrThrow(): Id {
+ return this.toLongOrNull()?.takeIf { it != Long.MIN_VALUE } ?: throw IllegalArgumentException("Invalid Id: $this")
+}
+
+inline fun String.toId(receiver: (Id) -> T?): T? {
+ return this.toId()?.let(receiver)
+}
diff --git a/shared/src/test/kotlin/io/github/truenine/composeserver/AliasExtensionsTest.kt b/shared/src/test/kotlin/io/github/truenine/composeserver/AliasExtensionsTest.kt
index bef4f794b..135cca293 100644
--- a/shared/src/test/kotlin/io/github/truenine/composeserver/AliasExtensionsTest.kt
+++ b/shared/src/test/kotlin/io/github/truenine/composeserver/AliasExtensionsTest.kt
@@ -4,85 +4,249 @@ import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull
+import kotlin.test.assertSame
import kotlin.test.assertTrue
+import kotlin.test.fail
-/** ID 类型相关扩展函数的测试类 */
class AliasExtensionsTest {
+ // Long.isId() tests
@Test
- fun `test long is id`() {
- assertFalse((-1L).isId(), "负数不是有效Id")
- assertTrue(0L.isId(), "0 是有效Id")
- assertTrue(1L.isId(), "正整数是有效Id")
- assertTrue(Long.MAX_VALUE.isId(), "Long最大值是有效Id")
- assertFalse(Long.MIN_VALUE.isId(), "Long最小值不是有效Id")
+ fun `Long isId() should return true for valid positive ids`() {
+ assertTrue(0L.isId(), "Zero should be a valid ID")
+ assertTrue(1L.isId(), "Positive integer should be a valid ID")
+ assertTrue(123L.isId(), "Any positive long should be a valid ID")
+ assertTrue(Long.MAX_VALUE.isId(), "Maximum long value should be a valid ID")
}
@Test
- fun `test string is id`() {
- assertFalse("".isId(), "空字符串不是有效Id")
- assertTrue("0".isId(), "0 是有效Id")
- assertTrue("123456".isId(), "全数字字符串是有效Id")
- assertTrue("000123".isId(), "前导0的数字字符串是有效Id")
- assertTrue("123a".isId(), "包含字母是有效Id")
- assertFalse("12 34".isId(), "包含空格不是有效Id")
- assertFalse("1234".isId(), "全角数字不是有效Id")
- assertFalse("123!".isId(), "包含符号不是有效Id")
- assertFalse("一二三".isId(), "中文不是有效Id")
- assertFalse("123.45".isId(), "小数不是有效Id")
- assertFalse(" 123".isId(), "前有空格不是有效Id")
- assertFalse("123 ".isId(), "后有空格不是有效Id")
- // 超大数字字符串(超出Long范围,但只要是数字也算有效)
- assertTrue("92233720368547758079223372036854775807".isId(), "超大数字字符串也是有效Id")
+ fun `Long isId() should return false for negative numbers`() {
+ assertFalse((-1L).isId(), "Negative one should not be a valid ID")
+ assertFalse((-123L).isId(), "Any negative number should not be a valid ID")
+ assertFalse(Long.MIN_VALUE.isId(), "Minimum long value should not be a valid ID")
}
+ // String.isId() tests
@Test
- fun `isId 当输入为有效Long类型ID时 返回true`() {
- assertTrue(1L.isId(), "正数 ID 应该返回 true")
- assertTrue(Long.MAX_VALUE.isId(), "最大 Long 值应该返回 true")
+ fun `String isId() should return true for valid alphanumeric strings`() {
+ assertTrue("a".isId(), "Single letter should be a valid ID")
+ assertTrue("A".isId(), "Single uppercase letter should be a valid ID")
+ assertTrue("0".isId(), "Single digit should be a valid ID")
+ assertTrue("abc123".isId(), "Mixed alphanumeric should be a valid ID")
+ assertTrue("ABC123".isId(), "Uppercase alphanumeric should be a valid ID")
+ assertTrue("123abc".isId(), "Digits followed by letters should be a valid ID")
+ assertTrue("a1b2c3".isId(), "Alternating letters and digits should be a valid ID")
+ assertTrue("000123".isId(), "Leading zeros should be allowed")
+ assertTrue("veryLongIdNameWithNumbers12345".isId(), "Long alphanumeric string should be valid")
}
@Test
- fun `isId 当输入为无效Long类型ID时 返回false`() {
- assertTrue(0L.isId(), "0 应该返回 true")
- assertFalse((-1L).isId(), "负数应该返回 false")
+ fun `String isId() should return false for empty strings`() {
+ assertFalse("".isId(), "Empty string should not be a valid ID")
}
@Test
- fun `isId 当输入为有效字符串ID时 返回true`() {
- assertTrue("123".isId(), "数字字符串应该返回 true")
- assertTrue("9999999999".isId(), "长数字字符串应该返回 true")
+ fun `String isId() should return false for strings with non-ASCII characters`() {
+ assertFalse("一二三".isId(), "Chinese characters should not be valid")
+ assertFalse("café".isId(), "Accented characters should not be valid")
+ assertFalse("naïve".isId(), "Special accented characters should not be valid")
+ assertFalse("Москва".isId(), "Cyrillic characters should not be valid")
}
@Test
- fun `isId 当输入为无效字符串ID时 返回false`() {
- assertFalse("".isId(), "空字符串应该返回 false")
- assertFalse("-123".isId(), "负数字符串应该返回 false")
+ fun `String isId() should return false for strings with spaces`() {
+ assertFalse("abc 123".isId(), "String with space should not be valid")
+ assertFalse(" abc123".isId(), "String with leading space should not be valid")
+ assertFalse("abc123 ".isId(), "String with trailing space should not be valid")
+ assertFalse("abc 123".isId(), "String with multiple spaces should not be valid")
}
@Test
- fun `toId 当输入为有效数字类型时 正确转换为ID`() {
- assertEquals(123L, 123.toId(), "Int类型应该正确转换")
- assertEquals(123L, 123L.toId(), "Long类型应该正确转换")
- assertEquals(123L, 123.0.toId(), "Double类型应该正确转换")
+ fun `String isId() should return false for strings with special characters`() {
+ assertFalse("abc@123".isId(), "String with @ symbol should not be valid")
+ assertFalse("abc-123".isId(), "String with hyphen should not be valid")
+ assertFalse("abc_123".isId(), "String with underscore should not be valid")
+ assertFalse("abc.123".isId(), "String with dot should not be valid")
+ assertFalse("abc/123".isId(), "String with slash should not be valid")
+ assertFalse("abc!123".isId(), "String with exclamation mark should not be valid")
+ assertFalse("abc#123".isId(), "String with hash symbol should not be valid")
+ assertFalse("abc$123".isId(), "String with dollar sign should not be valid")
+ assertFalse("abc%123".isId(), "String with percent sign should not be valid")
+ assertFalse("abc^123".isId(), "String with caret should not be valid")
+ assertFalse("abc&123".isId(), "String with ampersand should not be valid")
+ assertFalse("abc*123".isId(), "String with asterisk should not be valid")
+ assertFalse("abc(123)".isId(), "String with parentheses should not be valid")
+ assertFalse("abc[123]".isId(), "String with brackets should not be valid")
+ assertFalse("abc{123}".isId(), "String with braces should not be valid")
+ }
+
+ // getDefaultNullableId() tests - SKIPPED due to ERROR deprecation level
+ // This function is marked with DeprecationLevel.ERROR and should not be called by users
+
+ // Number.toId() tests
+ @Test
+ fun `Number toId() should convert valid numbers to ID`() {
+ assertEquals(1L, 1.toId(), "Int should convert to Long ID")
+ assertEquals(123L, 123.toId(), "Positive Int should convert to Long ID")
+ assertEquals(0L, 0.toId(), "Zero Int should convert to Long ID")
+ assertEquals(1L, 1L.toId(), "Long should remain as Long ID")
+ assertEquals(123L, 123L.toId(), "Positive Long should remain as Long ID")
+ assertEquals(0L, 0L.toId(), "Zero Long should remain as Long ID")
+ assertEquals(1L, 1.0.toId(), "Double 1.0 should convert to Long ID")
+ assertEquals(123L, 123.0.toId(), "Double 123.0 should convert to Long ID")
+ assertEquals(1L, 1.5.toId(), "Double 1.5 should truncate to 1L")
+ assertEquals(1L, (1.999999).toId(), "Double 1.999999 should truncate to 1L")
+ assertEquals(123L, 123.99.toId(), "Double 123.99 should truncate to 123L")
+ assertEquals(1L, 1.0f.toId(), "Float 1.0 should convert to Long ID")
+ assertEquals(123L, 123.0f.toId(), "Float 123.0 should convert to Long ID")
+ assertEquals(1L, 1.5f.toId(), "Float 1.5 should truncate to 1L")
+ assertEquals(1L, (1.999999f).toId(), "Float 1.999999 should truncate to 1L")
}
@Test
- fun `toId 当输入为无效数字类型时 返回null`() {
- assertNull(Long.MIN_VALUE.toId(), "Long.MIN_VALUE应该返回null")
+ fun `Number toId() should return null for Long MIN_VALUE`() {
+ assertNull(Long.MIN_VALUE.toId(), "Long.MIN_VALUE should return null")
}
+ // Number.toIdOrThrow() tests
@Test
- fun `toId 当输入为有效字符串时 正确转换为ID`() {
- assertEquals(123L, "123".toId(), "有效数字字符串应该正确转换")
- assertEquals(-123L, "-123".toId(), "负数字符串应该正确转换")
+ fun `Number toIdOrThrow() should convert valid numbers to ID`() {
+ assertEquals(1L, 1.toIdOrThrow(), "Int should convert to Long ID")
+ assertEquals(123L, 123.toIdOrThrow(), "Positive Int should convert to Long ID")
+ assertEquals(0L, 0.toIdOrThrow(), "Zero Int should convert to Long ID")
+ assertEquals(1L, 1L.toIdOrThrow(), "Long should remain as Long ID")
+ assertEquals(123L, 123L.toIdOrThrow(), "Positive Long should remain as Long ID")
+ assertEquals(0L, 0L.toIdOrThrow(), "Zero Long should remain as Long ID")
+ assertEquals(1L, 1.0.toIdOrThrow(), "Double 1.0 should convert to Long ID")
+ assertEquals(123L, 123.0.toIdOrThrow(), "Double 123.0 should convert to Long ID")
+ assertEquals(1L, 1.5.toIdOrThrow(), "Double 1.5 should truncate to 1L")
+ assertEquals(1L, (1.999999).toIdOrThrow(), "Double 1.999999 should truncate to 1L")
+ assertEquals(123L, 123.99.toIdOrThrow(), "Double 123.99 should truncate to 123L")
+ assertEquals(1L, 1.0f.toIdOrThrow(), "Float 1.0 should convert to Long ID")
+ assertEquals(123L, 123.0f.toIdOrThrow(), "Float 123.0 should convert to Long ID")
+ assertEquals(1L, 1.5f.toIdOrThrow(), "Float 1.5 should truncate to 1L")
+ assertEquals(1L, (1.999999f).toIdOrThrow(), "Float 1.999999 should truncate to 1L")
}
@Test
- fun `toId 当输入为无效字符串时 返回null`() {
- assertNull("".toId(), "空字符串应该返回null")
- assertNull("abc".toId(), "非数字字符串应该返回null")
- assertNull("123abc".toId(), "混合字符串应该返回null")
- assertNull(Long.MIN_VALUE.toString().toId(), "Long.MIN_VALUE字符串应该返回null")
+ fun `Number toIdOrThrow() should throw exception for Long MIN_VALUE`() {
+ try {
+ Long.MIN_VALUE.toIdOrThrow()
+ fail("Expected IllegalArgumentException to be thrown")
+ } catch (e: IllegalArgumentException) {
+ assertEquals("Invalid Id: ${Long.MIN_VALUE}", e.message, "Exception message should contain the invalid ID")
+ }
+ }
+
+ // String.toId() tests
+ @Test
+ fun `String toId() should convert valid numeric strings to ID`() {
+ assertEquals(1L, "1".toId(), "String '1' should convert to Long 1")
+ assertEquals(123L, "123".toId(), "String '123' should convert to Long 123")
+ assertEquals(0L, "0".toId(), "String '0' should convert to Long 0")
+ assertEquals(-1L, "-1".toId(), "String '-1' should convert to Long -1")
+ assertEquals(-123L, "-123".toId(), "String '-123' should convert to Long -123")
+ assertEquals(Long.MAX_VALUE, Long.MAX_VALUE.toString().toId(), "Max long string should convert to max long")
+ assertEquals(Long.MIN_VALUE + 1, (Long.MIN_VALUE + 1).toString().toId(), "Min long + 1 string should convert")
+ }
+
+ @Test
+ fun `String toId() should return null for invalid numeric strings`() {
+ assertNull("".toId(), "Empty string should return null")
+ assertNull("abc".toId(), "Non-numeric string should return null")
+ assertNull("123abc".toId(), "Mixed alphanumeric string should return null")
+ assertNull("abc123".toId(), "Letters followed by numbers should return null")
+ assertNull("12.34".toId(), "Decimal string should return null")
+ assertNull("12,34".toId(), "String with comma should return null")
+ assertNull(" 123".toId(), "String with leading space should return null")
+ assertNull("123 ".toId(), "String with trailing space should return null")
+ assertNull("12 34".toId(), "String with internal space should return null")
+ assertNull("++123".toId(), "String with double plus should return null")
+ assertNull("--123".toId(), "String with double minus should return null")
+ assertNull("1a2b3c".toId(), "Mixed alphanumeric should return null")
+ assertNull(Long.MIN_VALUE.toString().toId(), "Long.MIN_VALUE string should return null")
+ }
+
+ @Test
+ fun `String toId() should correctly handle strings with plus sign`() {
+ assertEquals(123L, "+123".toId(), "String with plus sign should be parsed correctly")
+ }
+
+ // String.toIdOrThrow() tests
+ @Test
+ fun `String toIdOrThrow() should convert valid numeric strings to ID`() {
+ assertEquals(1L, "1".toIdOrThrow(), "String '1' should convert to Long 1")
+ assertEquals(123L, "123".toIdOrThrow(), "String '123' should convert to Long 123")
+ assertEquals(0L, "0".toIdOrThrow(), "String '0' should convert to Long 0")
+ assertEquals(-1L, "-1".toIdOrThrow(), "String '-1' should convert to Long -1")
+ assertEquals(-123L, "-123".toIdOrThrow(), "String '-123' should convert to Long -123")
+ assertEquals(Long.MAX_VALUE, Long.MAX_VALUE.toString().toIdOrThrow(), "Max long string should convert to max long")
+ assertEquals(Long.MIN_VALUE + 1, (Long.MIN_VALUE + 1).toString().toIdOrThrow(), "Min long + 1 string should convert")
+ }
+
+ @Test
+ fun `String toIdOrThrow() should throw exception for invalid numeric strings`() {
+ val invalidInputs = listOf(
+ "", "abc", "123abc", "abc123", "12.34", "12,34", " 123", "123 ", "12 34",
+ "++123", "--123", "1a2b3c", Long.MIN_VALUE.toString()
+ )
+
+ invalidInputs.forEach { input ->
+ try {
+ input.toIdOrThrow()
+ fail("Expected IllegalArgumentException to be thrown for input: $input")
+ } catch (e: IllegalArgumentException) {
+ assertEquals("Invalid Id: $input", e.message, "Exception message should contain the invalid ID")
+ }
+ }
+ }
+
+ @Test
+ fun `String toIdOrThrow() should correctly handle strings with plus sign`() {
+ assertEquals(123L, "+123".toIdOrThrow(), "String with plus sign should be parsed correctly")
+ }
+
+ // Number.toId with receiver function tests
+ @Test
+ fun `Number toId() with receiver should apply function when valid ID`() {
+ val result1 = 123.toId { it * 2 }
+ assertEquals(246L, result1, "Should apply function to valid ID")
+
+ val result2 = 0.toId { it.toString() }
+ assertEquals("0", result2, "Should apply function to zero ID")
+
+ val result3 = 1.5.toId { it + 100 }
+ assertEquals(101L, result3, "Should truncate and apply function")
+ }
+
+ @Test
+ fun `Number toId() with receiver should return null when invalid ID`() {
+ val result1 = Long.MIN_VALUE.toId { it * 2 }
+ assertNull(result1, "Should return null for invalid ID")
+ }
+
+ // String.toId with receiver function tests
+ @Test
+ fun `String toId() with receiver should apply function when valid ID`() {
+ val result1 = "123".toId { it * 2 }
+ assertEquals(246L, result1, "Should apply function to valid ID")
+
+ val result2 = "0".toId { it.toString() }
+ assertEquals("0", result2, "Should apply function to zero ID")
+
+ val result3 = "-456".toId { it + 100 }
+ assertEquals(-356L, result3, "Should apply function to negative ID")
+ }
+
+ @Test
+ fun `String toId() with receiver should return null when invalid ID`() {
+ val result1 = "".toId { it * 2 }
+ assertNull(result1, "Should return null for empty string")
+
+ val result2 = "abc".toId { it.toString() }
+ assertNull(result2, "Should return null for non-numeric string")
+
+ val result3 = Long.MIN_VALUE.toString().toId { it + 100 }
+ assertNull(result3, "Should return null for Long.MIN_VALUE string")
}
-}
+}
\ No newline at end of file
diff --git a/todolist.md b/todolist.md
index 0da9c9a45..9035959d9 100644
--- a/todolist.md
+++ b/todolist.md
@@ -1,7 +1,3 @@
-# coding
-
+- [ ] 重写所有集成测试支持 `EnableIf`
- [ ] write `testtoolkit-testcontainers` testcontainers simple launcher
-
-# claude code
-
- [ ] write claude code setup slash command