@@ -158,3 +158,67 @@ TEST(AttributesHashMap, HashConsistencyAcrossStringTypes)
158158  EXPECT_EQ (hash_c_str, hash_std_str_view);
159159#endif 
160160}
161+ 
162+ TEST (AttributesHashMap, OverflowCardinalityLimitBehavior)
163+ {
164+   //  Configure a very small limit to exercise overflow logic easily.
165+   const  size_t  limit = 4 ;  //  real attributes limit
166+   AttributesHashMapWithCustomHash<> map (limit);
167+ 
168+   //  We expect to be able to insert exactly 'limit' distinct real attribute sets.
169+   //  After that, further distinct attributes should route to the overflow bucket,
170+   //  which should appear only once regardless of how many additional unique sets arrive.
171+ 
172+   //  Insert distinct attributes up to the limit.
173+   for  (size_t  i = 0 ; i < limit; ++i)
174+   {
175+     MetricAttributes attr = {{" k"  , std::to_string (i)}};
176+     map.GetOrSetDefault (attr, []() { return  std::unique_ptr<Aggregation>(new  DropAggregation ()); })
177+         ->Aggregate (static_cast <int64_t >(1 ));
178+   }
179+ 
180+   //  Size should be exactly 'limit' (no overflow yet)
181+   EXPECT_EQ (map.Size (), limit);
182+ 
183+   //  Insert one more distinct attribute; this should not increase the real attributes count
184+   MetricAttributes overflow_trigger = {{" k"  , " overflow"  }};
185+   map.GetOrSetDefault (overflow_trigger,
186+                       []() { return  std::unique_ptr<Aggregation>(new  DropAggregation ()); })
187+       ->Aggregate (static_cast <int64_t >(1 ));
188+ 
189+   EXPECT_EQ (map.Size (), limit);
190+ 
191+   //  Insert several more unique attributes - size must remain constant (limit)
192+   for  (size_t  i = 0 ; i < limit - 1 ; ++i)
193+   {
194+     MetricAttributes extra_attr = {{" k"  , std::string (" extra"  ) + std::to_string (i)}};
195+     map.GetOrSetDefault (extra_attr,
196+                         []() { return  std::unique_ptr<Aggregation>(new  DropAggregation ()); })
197+         ->Aggregate (static_cast <int64_t >(1 ));
198+   }
199+   EXPECT_EQ (map.Size (), limit);
200+ 
201+   //  Ensure overflow key was actually created and accessible via Get
202+   EXPECT_NE (map.Get (kOverflowAttributes ), nullptr );
203+ 
204+   //  Ensure original real attributes still present
205+   for  (size_t  i = 0 ; i < limit - 1 ; ++i)
206+   {
207+     MetricAttributes attr = {{" k"  , std::to_string (i)}};
208+     EXPECT_NE (map.Get (attr), nullptr );
209+   }
210+ 
211+   //  Copy the hash map to a new map in non-determistic order and verify all entries are present
212+   AttributesHashMapWithCustomHash<> map_copy (limit);
213+   map.GetAllEnteries ([&map_copy](const  MetricAttributes &attributes, Aggregation &) {
214+     map_copy.Set (attributes, std::unique_ptr<Aggregation>(new  DropAggregation ()));
215+     return  true ;
216+   });
217+   EXPECT_EQ (map_copy.Size (), map.Size ());
218+   EXPECT_NE (map_copy.Get (kOverflowAttributes ), nullptr );
219+   for  (size_t  i = 0 ; i < limit - 1 ; ++i)
220+   {
221+     MetricAttributes attr = {{" k"  , std::to_string (i)}};
222+     EXPECT_NE (map_copy.Get (attr), nullptr );
223+   }
224+ }
0 commit comments