@@ -242,4 +242,292 @@ mod tests {
242242 assert_eq ! ( cache. hits( ) , 0 ) ;
243243 assert_eq ! ( cache. misses( ) , 0 ) ;
244244 }
245+
246+ // =========================================================================
247+ // CacheKey Tests
248+ // =========================================================================
249+
250+ #[ test]
251+ fn test_cache_key_equality ( ) {
252+ let key1 = CacheKey {
253+ widget_id : 1 ,
254+ constraints_hash : 100 ,
255+ } ;
256+ let key2 = CacheKey {
257+ widget_id : 1 ,
258+ constraints_hash : 100 ,
259+ } ;
260+ assert_eq ! ( key1, key2) ;
261+ }
262+
263+ #[ test]
264+ fn test_cache_key_inequality_widget_id ( ) {
265+ let key1 = CacheKey {
266+ widget_id : 1 ,
267+ constraints_hash : 100 ,
268+ } ;
269+ let key2 = CacheKey {
270+ widget_id : 2 ,
271+ constraints_hash : 100 ,
272+ } ;
273+ assert_ne ! ( key1, key2) ;
274+ }
275+
276+ #[ test]
277+ fn test_cache_key_inequality_constraints ( ) {
278+ let key1 = CacheKey {
279+ widget_id : 1 ,
280+ constraints_hash : 100 ,
281+ } ;
282+ let key2 = CacheKey {
283+ widget_id : 1 ,
284+ constraints_hash : 200 ,
285+ } ;
286+ assert_ne ! ( key1, key2) ;
287+ }
288+
289+ #[ test]
290+ fn test_cache_key_clone ( ) {
291+ let key = CacheKey {
292+ widget_id : 42 ,
293+ constraints_hash : 999 ,
294+ } ;
295+ let cloned = key;
296+ assert_eq ! ( key, cloned) ;
297+ }
298+
299+ #[ test]
300+ fn test_cache_key_debug ( ) {
301+ let key = CacheKey {
302+ widget_id : 1 ,
303+ constraints_hash : 100 ,
304+ } ;
305+ let debug = format ! ( "{:?}" , key) ;
306+ assert ! ( debug. contains( "widget_id" ) ) ;
307+ assert ! ( debug. contains( "constraints_hash" ) ) ;
308+ }
309+
310+ // =========================================================================
311+ // Multiple Entries Tests
312+ // =========================================================================
313+
314+ #[ test]
315+ fn test_cache_multiple_entries ( ) {
316+ let mut cache = LayoutCache :: new ( ) ;
317+
318+ for i in 0 ..10 {
319+ let key = CacheKey {
320+ widget_id : i,
321+ constraints_hash : i * 100 ,
322+ } ;
323+ cache. insert ( key, Size :: new ( i as f32 , i as f32 ) ) ;
324+ }
325+
326+ assert_eq ! ( cache. len( ) , 10 ) ;
327+
328+ // Verify each entry
329+ for i in 0 ..10 {
330+ let key = CacheKey {
331+ widget_id : i,
332+ constraints_hash : i * 100 ,
333+ } ;
334+ assert_eq ! ( cache. get( key) , Some ( Size :: new( i as f32 , i as f32 ) ) ) ;
335+ }
336+ }
337+
338+ #[ test]
339+ fn test_cache_overwrite_entry ( ) {
340+ let mut cache = LayoutCache :: new ( ) ;
341+ let key = CacheKey {
342+ widget_id : 1 ,
343+ constraints_hash : 100 ,
344+ } ;
345+
346+ cache. insert ( key, Size :: new ( 10.0 , 10.0 ) ) ;
347+ assert_eq ! ( cache. get( key) , Some ( Size :: new( 10.0 , 10.0 ) ) ) ;
348+
349+ // Overwrite with new size
350+ cache. insert ( key, Size :: new ( 20.0 , 20.0 ) ) ;
351+ assert_eq ! ( cache. get( key) , Some ( Size :: new( 20.0 , 20.0 ) ) ) ;
352+ assert_eq ! ( cache. len( ) , 1 ) ;
353+ }
354+
355+ // =========================================================================
356+ // Eviction Edge Cases
357+ // =========================================================================
358+
359+ #[ test]
360+ fn test_cache_eviction_threshold ( ) {
361+ let mut cache = LayoutCache :: new ( ) ;
362+
363+ let key1 = CacheKey {
364+ widget_id : 1 ,
365+ constraints_hash : 100 ,
366+ } ;
367+ let key2 = CacheKey {
368+ widget_id : 2 ,
369+ constraints_hash : 200 ,
370+ } ;
371+
372+ cache. insert ( key1, Size :: new ( 10.0 , 10.0 ) ) ;
373+ cache. advance_frame ( ) ;
374+ cache. insert ( key2, Size :: new ( 20.0 , 20.0 ) ) ;
375+ cache. advance_frame ( ) ;
376+
377+ // Both should still be present (threshold is 2 frames)
378+ assert_eq ! ( cache. len( ) , 2 ) ;
379+
380+ // One more frame without touching key1
381+ let _ = cache. get ( key2) ;
382+ cache. advance_frame ( ) ;
383+
384+ // key1 should be evicted (not used in last 2 frames)
385+ assert_eq ! ( cache. len( ) , 1 ) ;
386+ assert_eq ! ( cache. get( key2) , Some ( Size :: new( 20.0 , 20.0 ) ) ) ;
387+ }
388+
389+ #[ test]
390+ fn test_cache_eviction_empty_cache ( ) {
391+ let mut cache = LayoutCache :: new ( ) ;
392+
393+ // Advancing frames on empty cache should not panic
394+ for _ in 0 ..10 {
395+ cache. advance_frame ( ) ;
396+ }
397+
398+ assert ! ( cache. is_empty( ) ) ;
399+ }
400+
401+ // =========================================================================
402+ // Default Implementation
403+ // =========================================================================
404+
405+ #[ test]
406+ fn test_cache_default ( ) {
407+ let cache = LayoutCache :: default ( ) ;
408+ assert ! ( cache. is_empty( ) ) ;
409+ assert_eq ! ( cache. hits( ) , 0 ) ;
410+ assert_eq ! ( cache. misses( ) , 0 ) ;
411+ }
412+
413+ // =========================================================================
414+ // Debug Format
415+ // =========================================================================
416+
417+ #[ test]
418+ fn test_cache_debug ( ) {
419+ let cache = LayoutCache :: new ( ) ;
420+ let debug = format ! ( "{:?}" , cache) ;
421+ assert ! ( debug. contains( "LayoutCache" ) ) ;
422+ }
423+
424+ // =========================================================================
425+ // Size Values
426+ // =========================================================================
427+
428+ #[ test]
429+ fn test_cache_with_zero_size ( ) {
430+ let mut cache = LayoutCache :: new ( ) ;
431+ let key = CacheKey {
432+ widget_id : 1 ,
433+ constraints_hash : 100 ,
434+ } ;
435+
436+ cache. insert ( key, Size :: new ( 0.0 , 0.0 ) ) ;
437+ assert_eq ! ( cache. get( key) , Some ( Size :: new( 0.0 , 0.0 ) ) ) ;
438+ }
439+
440+ #[ test]
441+ fn test_cache_with_large_size ( ) {
442+ let mut cache = LayoutCache :: new ( ) ;
443+ let key = CacheKey {
444+ widget_id : 1 ,
445+ constraints_hash : 100 ,
446+ } ;
447+
448+ cache. insert ( key, Size :: new ( 10000.0 , 10000.0 ) ) ;
449+ assert_eq ! ( cache. get( key) , Some ( Size :: new( 10000.0 , 10000.0 ) ) ) ;
450+ }
451+
452+ #[ test]
453+ fn test_cache_with_fractional_size ( ) {
454+ let mut cache = LayoutCache :: new ( ) ;
455+ let key = CacheKey {
456+ widget_id : 1 ,
457+ constraints_hash : 100 ,
458+ } ;
459+
460+ cache. insert ( key, Size :: new ( 10.5 , 20.75 ) ) ;
461+ assert_eq ! ( cache. get( key) , Some ( Size :: new( 10.5 , 20.75 ) ) ) ;
462+ }
463+
464+ // =========================================================================
465+ // Hash Collision Resistance
466+ // =========================================================================
467+
468+ #[ test]
469+ fn test_cache_different_widget_same_constraints ( ) {
470+ let mut cache = LayoutCache :: new ( ) ;
471+
472+ let key1 = CacheKey {
473+ widget_id : 1 ,
474+ constraints_hash : 100 ,
475+ } ;
476+ let key2 = CacheKey {
477+ widget_id : 2 ,
478+ constraints_hash : 100 ,
479+ } ;
480+
481+ cache. insert ( key1, Size :: new ( 10.0 , 10.0 ) ) ;
482+ cache. insert ( key2, Size :: new ( 20.0 , 20.0 ) ) ;
483+
484+ assert_eq ! ( cache. get( key1) , Some ( Size :: new( 10.0 , 10.0 ) ) ) ;
485+ assert_eq ! ( cache. get( key2) , Some ( Size :: new( 20.0 , 20.0 ) ) ) ;
486+ assert_eq ! ( cache. len( ) , 2 ) ;
487+ }
488+
489+ #[ test]
490+ fn test_cache_same_widget_different_constraints ( ) {
491+ let mut cache = LayoutCache :: new ( ) ;
492+
493+ let key1 = CacheKey {
494+ widget_id : 1 ,
495+ constraints_hash : 100 ,
496+ } ;
497+ let key2 = CacheKey {
498+ widget_id : 1 ,
499+ constraints_hash : 200 ,
500+ } ;
501+
502+ cache. insert ( key1, Size :: new ( 10.0 , 10.0 ) ) ;
503+ cache. insert ( key2, Size :: new ( 20.0 , 20.0 ) ) ;
504+
505+ assert_eq ! ( cache. get( key1) , Some ( Size :: new( 10.0 , 10.0 ) ) ) ;
506+ assert_eq ! ( cache. get( key2) , Some ( Size :: new( 20.0 , 20.0 ) ) ) ;
507+ assert_eq ! ( cache. len( ) , 2 ) ;
508+ }
509+
510+ // =========================================================================
511+ // Frame Counter
512+ // =========================================================================
513+
514+ #[ test]
515+ fn test_cache_frame_counter_overflow ( ) {
516+ let mut cache = LayoutCache :: new ( ) ;
517+ let key = CacheKey {
518+ widget_id : 1 ,
519+ constraints_hash : 100 ,
520+ } ;
521+
522+ cache. insert ( key, Size :: new ( 10.0 , 10.0 ) ) ;
523+
524+ // Advance many frames while keeping entry fresh
525+ for _ in 0 ..100 {
526+ let _ = cache. get ( key) ;
527+ cache. advance_frame ( ) ;
528+ }
529+
530+ // Entry should still exist
531+ assert_eq ! ( cache. get( key) , Some ( Size :: new( 10.0 , 10.0 ) ) ) ;
532+ }
245533}
0 commit comments