1+ package taboolib.common.util
2+
3+ import org.junit.jupiter.api.Test
4+ import org.junit.jupiter.api.Assertions.*
5+
6+ class SupplierLazyTest {
7+
8+ @Test
9+ fun `test basic supplier lazy initialization` () {
10+ var initCount = 0
11+ val lazy = supplierLazy<String , String > { context ->
12+ initCount++
13+ " Hello $context "
14+ }
15+
16+ assertFalse(lazy.isInitialized())
17+
18+ val result1 = lazy[" World" ]
19+ assertEquals(" Hello World" , result1)
20+ assertEquals(1 , initCount)
21+ assertTrue(lazy.isInitialized())
22+
23+ // Should return cached value, not reinitialize
24+ val result2 = lazy[" Different" ]
25+ assertEquals(" Hello World" , result2)
26+ assertEquals(1 , initCount)
27+ }
28+
29+ @Test
30+ fun `test supplier lazy with null value` () {
31+ val lazy = supplierLazy<String , String ?> { null }
32+
33+ assertFalse(lazy.isInitialized())
34+ val result = lazy[" test" ]
35+ assertNull(result)
36+ assertTrue(lazy.isInitialized())
37+ }
38+
39+ @Test
40+ fun `test supplier lazy reset` () {
41+ var initCount = 0
42+ val lazy = supplierLazy<Int , String > { context ->
43+ initCount++
44+ " Count: $context "
45+ }
46+
47+ lazy[1 ]
48+ assertEquals(1 , initCount)
49+ assertTrue(lazy.isInitialized())
50+
51+ lazy.reset()
52+ assertFalse(lazy.isInitialized())
53+
54+ lazy[2 ]
55+ assertEquals(2 , initCount)
56+ assertTrue(lazy.isInitialized())
57+ }
58+
59+ @Test
60+ fun `test supplier lazy with type isolation disabled` () {
61+ var initCount = 0
62+ val lazy = supplierLazy<Any , String >(typeIsolation = false ) { context ->
63+ initCount++
64+ " Value: ${context::class .simpleName} "
65+ }
66+
67+ val result1 = lazy[" String" ]
68+ assertEquals(" Value: String" , result1)
69+ assertEquals(1 , initCount)
70+
71+ // Different type but should return cached value
72+ val result2 = lazy[123 ]
73+ assertEquals(" Value: String" , result2)
74+ assertEquals(1 , initCount)
75+ }
76+
77+ @Test
78+ fun `test supplier lazy with type isolation enabled` () {
79+ var initCount = 0
80+ val lazy = supplierLazy<Any , String >(typeIsolation = true ) { context ->
81+ initCount++
82+ " Value: ${context::class .simpleName} -$context "
83+ }
84+
85+ assertFalse(lazy.isInitialized())
86+
87+ val result1 = lazy[" String" ]
88+ assertEquals(" Value: String-String" , result1)
89+ assertEquals(1 , initCount)
90+ assertTrue(lazy.isInitialized())
91+
92+ // Different type should reinitialize
93+ val result2 = lazy[123 ]
94+ assertEquals(" Value: Int-123" , result2)
95+ assertEquals(2 , initCount)
96+
97+ // Same type as first should return cached value
98+ val result3 = lazy[" Different" ]
99+ assertEquals(" Value: String-String" , result3)
100+ assertEquals(2 , initCount)
101+
102+ // Same type as second should return cached value
103+ val result4 = lazy[456 ]
104+ assertEquals(" Value: Int-123" , result4)
105+ assertEquals(2 , initCount)
106+ }
107+
108+ @Test
109+ fun `test supplier lazy with type isolation and null values` () {
110+ var initCount = 0
111+ val lazy = supplierLazy<Any , String ?>(typeIsolation = true ) { context ->
112+ initCount++
113+ when (context) {
114+ is String -> " String: $context "
115+ is Int -> null
116+ else -> " Other: $context "
117+ }
118+ }
119+
120+ val result1 = lazy[" test" ]
121+ assertEquals(" String: test" , result1)
122+ assertEquals(1 , initCount)
123+
124+ val result2 = lazy[42 ]
125+ assertNull(result2)
126+ assertEquals(2 , initCount)
127+
128+ val result3 = lazy[99 ]
129+ assertNull(result3)
130+ assertEquals(2 , initCount) // Should use cached null value
131+ }
132+
133+ @Test
134+ fun `test supplier lazy with type isolation reset` () {
135+ var initCount = 0
136+ val lazy = supplierLazy<Any , String >(typeIsolation = true ) { context ->
137+ initCount++
138+ " Init: $initCount "
139+ }
140+
141+ lazy[" String" ]
142+ lazy[123 ]
143+ assertEquals(2 , initCount)
144+ assertTrue(lazy.isInitialized())
145+
146+ lazy.reset()
147+ assertFalse(lazy.isInitialized())
148+
149+ lazy[" NewString" ]
150+ lazy[456 ]
151+ assertEquals(4 , initCount)
152+ }
153+
154+ @Test
155+ fun `test supplier lazy with custom classes` () {
156+ data class Person (val name : String )
157+ data class Animal (val species : String )
158+
159+ val lazy = supplierLazy<Any , String >(typeIsolation = true ) { context ->
160+ when (context) {
161+ is Person -> " Person: ${context.name} "
162+ is Animal -> " Animal: ${context.species} "
163+ else -> " Unknown"
164+ }
165+ }
166+
167+ val result1 = lazy[Person (" Alice" )]
168+ assertEquals(" Person: Alice" , result1)
169+
170+ val result2 = lazy[Animal (" Dog" )]
171+ assertEquals(" Animal: Dog" , result2)
172+
173+ // Same type should return cached
174+ val result3 = lazy[Person (" Bob" )]
175+ assertEquals(" Person: Alice" , result3)
176+
177+ val result4 = lazy[Animal (" Cat" )]
178+ assertEquals(" Animal: Dog" , result4)
179+ }
180+
181+ @Test
182+ fun `test supplier lazy toString` () {
183+ val lazy1 = supplierLazy<String , Int > { it.length }
184+ assertTrue(lazy1.toString().contains(" not initialized" ))
185+
186+ lazy1[" test" ]
187+ assertFalse(lazy1.toString().contains(" not initialized" ))
188+
189+ val lazy2 = supplierLazy<String , Int >(typeIsolation = true ) { it.length }
190+ assertTrue(lazy2.toString().contains(" not initialized" ))
191+
192+ lazy2[" test" ]
193+ assertTrue(lazy2.toString().contains(" typeIsolation" ))
194+ assertTrue(lazy2.toString().contains(" 1 type(s)" ))
195+ }
196+
197+ @Test
198+ fun `test wrapped context basic isolation` () {
199+ var initCount = 0
200+ val lazy = supplierLazy<WrappedContext <Any , String >, String > (typeIsolation = true ) { ctx ->
201+ initCount++
202+ " ${ctx.context} :${ctx.extra} "
203+ }
204+
205+ val c1: WrappedContext <Any , String > = WrappedContext (" user" as Any , " a" )
206+ val c2: WrappedContext <Any , String > = WrappedContext (" user" as Any , " b" )
207+ val c3: WrappedContext <Any , String > = WrappedContext (123 as Any , " x" )
208+
209+ // 同一个 context 类型(String),虽然 extra 不同,但因为按 context.class 做隔离,只初始化一次
210+ val r1 = lazy[c1]
211+ val r2 = lazy[c2]
212+ assertEquals(" user:a" , r1)
213+ assertEquals(" user:a" , r2)
214+ assertEquals(1 , initCount)
215+
216+ // 不同 context 类型(Int),会使用另一份缓存
217+ val r3 = lazy[c3]
218+ assertEquals(" 123:x" , r3)
219+ assertEquals(2 , initCount)
220+ }
221+
222+ @Test
223+ fun `test wrapped context mixed with plain context` () {
224+ var initCount = 0
225+ val lazy = supplierLazy<Any , String >(typeIsolation = true ) { ctx ->
226+ initCount++
227+ when (ctx) {
228+ is WrappedContext <* , * > -> " wrapped:${ctx.context} :${ctx.extra} "
229+ else -> " plain:$ctx "
230+ }
231+ }
232+
233+ val plain: Any = " user"
234+ val wrapped1: Any = WrappedContext (" user" , " a" )
235+ val wrapped2: Any = WrappedContext (" user" , " b" )
236+
237+ // 第一次:普通 String 上下文
238+ val rPlain1 = lazy[plain]
239+ assertEquals(" plain:user" , rPlain1)
240+ assertEquals(1 , initCount)
241+
242+ // 第二次:WrappedContext,同样的 context 类型 String,但因为 SupplierLazyWithTypeIsolationImpl
243+ // 对 WrappedContext 使用 context.context::class.java 作为 key,会与 plain 的 String 类型共用缓存
244+ val rWrapped1 = lazy[wrapped1]
245+ assertEquals(" plain:user" , rWrapped1)
246+ assertEquals(1 , initCount)
247+
248+ // 第三次:另一个 WrappedContext,仍然命中同一个 String 类型缓存
249+ val rWrapped2 = lazy[wrapped2]
250+ assertEquals(" plain:user" , rWrapped2)
251+ assertEquals(1 , initCount)
252+
253+ // 验证 Int 类型仍然是独立的缓存 key
254+ val rInt1 = lazy[123 as Any ]
255+ assertEquals(" plain:123" , rInt1)
256+ assertEquals(2 , initCount)
257+ }
258+
259+ @Test
260+ fun `test wrapped context reset isolation map` () {
261+ var initCount = 0
262+ val lazy = supplierLazy<WrappedContext <Any , String >, String > (typeIsolation = true ) { ctx ->
263+ initCount++
264+ " ${ctx.context} :${ctx.extra} :$initCount "
265+ }
266+
267+ val sCtx: WrappedContext <Any , String > = WrappedContext (" user" as Any , " a" )
268+ val iCtx: WrappedContext <Any , String > = WrappedContext (1 as Any , " x" )
269+
270+ val r1 = lazy[sCtx]
271+ val r2 = lazy[iCtx]
272+ assertEquals(" user:a:1" , r1)
273+ assertEquals(" 1:x:2" , r2)
274+ assertEquals(2 , initCount)
275+
276+ lazy.reset()
277+ assertFalse(lazy.isInitialized())
278+
279+ val r3 = lazy[sCtx]
280+ val r4 = lazy[iCtx]
281+ assertEquals(" user:a:3" , r3)
282+ assertEquals(" 1:x:4" , r4)
283+ assertEquals(4 , initCount)
284+ }
285+ }
0 commit comments