@@ -217,3 +217,228 @@ test("minBy and maxBy functions with edge cases", () => {
217217 expect ( Lang . minBy ( nanArr , ( x ) => x . value ) ) . toEqual ( { value : NaN } ) ;
218218 expect ( Lang . maxBy ( nanArr , ( x ) => x . value ) ) . toEqual ( { value : NaN } ) ;
219219} ) ;
220+
221+ test ( "MultiLevelMap set and get" , ( ) => {
222+ const map = new Lang . MultiLevelMap < number > ( ) ;
223+ map . set ( [ "a" , "b" , "c" ] , 42 ) ;
224+ expect ( map . get ( [ "a" , "b" , "c" ] ) ) . toBe ( 42 ) ;
225+ // Attempt to get a value with an incomplete key path should return undefined.
226+ expect ( map . get ( [ "a" , "b" ] ) ) . toBeUndefined ( ) ;
227+ } ) ;
228+
229+ test ( "MultiLevelMap getAll returns all values under a branch" , ( ) => {
230+ const map = new Lang . MultiLevelMap < string > ( ) ;
231+ map . set ( [ "user" , "alice" ] , "AliceData" ) ;
232+ map . set ( [ "user" , "bob" ] , "BobData" ) ;
233+ map . set ( [ "user" , "charlie" ] , "CharlieData" ) ;
234+ map . set ( [ "system" , "config" ] , "SysConfig" ) ;
235+
236+ const userValues = map . getAll ( [ "user" ] ) ;
237+ expect ( userValues . sort ( ) ) . toEqual (
238+ [ "AliceData" , "BobData" , "CharlieData" ] . sort ( ) ,
239+ ) ;
240+
241+ // For a key path that doesn't exist, getAll should return an empty array.
242+ expect ( map . getAll ( [ "nonexistent" ] ) ) . toEqual ( [ ] ) ;
243+ } ) ;
244+
245+ test ( "MultiLevelMap has function" , ( ) => {
246+ const map = new Lang . MultiLevelMap < boolean > ( ) ;
247+ expect ( map . has ( [ "settings" , "theme" ] ) ) . toBe ( false ) ;
248+ map . set ( [ "settings" , "theme" ] , true ) ;
249+ expect ( map . has ( [ "settings" , "theme" ] ) ) . toBe ( true ) ;
250+ } ) ;
251+
252+ test ( "MultiLevelMap delete function removes entry and cleans up empty nodes" , ( ) => {
253+ const map = new Lang . MultiLevelMap < number > ( ) ;
254+ map . set ( [ "a" , "b" , "c" ] , 100 ) ;
255+ map . set ( [ "a" , "b" , "d" ] , 200 ) ;
256+ expect ( map . get ( [ "a" , "b" , "c" ] ) ) . toBe ( 100 ) ;
257+ expect ( map . get ( [ "a" , "b" , "d" ] ) ) . toBe ( 200 ) ;
258+
259+ // Delete one entry
260+ expect ( map . delete ( [ "a" , "b" , "c" ] ) ) . toBe ( true ) ;
261+ expect ( map . get ( [ "a" , "b" , "c" ] ) ) . toBeUndefined ( ) ;
262+ // The other entry should still exist
263+ expect ( map . get ( [ "a" , "b" , "d" ] ) ) . toBe ( 200 ) ;
264+
265+ // Attempt deleting a non-existent key path
266+ expect ( map . delete ( [ "a" , "b" , "c" ] ) ) . toBe ( false ) ;
267+ } ) ;
268+
269+ test ( "MultiLevelMap delete cleans up nodes without values" , ( ) => {
270+ const map = new Lang . MultiLevelMap < string > ( ) ;
271+ map . set ( [ "x" , "y" , "z" ] , "deepValue" ) ;
272+ // Delete the deep value.
273+ expect ( map . delete ( [ "x" , "y" , "z" ] ) ) . toBe ( true ) ;
274+ // After deletion, getAll from the branch should be empty.
275+ expect ( map . getAll ( [ "x" ] ) ) . toEqual ( [ ] ) ;
276+ } ) ;
277+ test ( "MultiLevelMap overwrites value if set with same keys" , ( ) => {
278+ const map = new Lang . MultiLevelMap < number > ( ) ;
279+ map . set ( [ "a" , "b" ] , 1 ) ;
280+ expect ( map . get ( [ "a" , "b" ] ) ) . toBe ( 1 ) ;
281+ // Overwrite the value at the same key path.
282+ map . set ( [ "a" , "b" ] , 2 ) ;
283+ expect ( map . get ( [ "a" , "b" ] ) ) . toBe ( 2 ) ;
284+ } ) ;
285+
286+ test ( "MultiLevelMap getAll returns only values under branch" , ( ) => {
287+ const map = new Lang . MultiLevelMap < string > ( ) ;
288+ map . set ( [ "section" , "item1" ] , "value1" ) ;
289+ map . set ( [ "section" , "subsection" , "item2" ] , "value2" ) ;
290+ map . set ( [ "section" , "subsection" , "item3" ] , "value3" ) ;
291+ map . set ( [ "section" , "other" ] , "value4" ) ;
292+ map . set ( [ "otherSection" , "item" ] , "value5" ) ;
293+
294+ const results = map . getAll ( [ "section" ] ) ;
295+ expect ( results . sort ( ) ) . toEqual (
296+ [ "value1" , "value2" , "value3" , "value4" ] . sort ( ) ,
297+ ) ;
298+ } ) ;
299+
300+ test ( "MultiLevelMap deleting branch cleans intermediate nodes" , ( ) => {
301+ const map = new Lang . MultiLevelMap < number > ( ) ;
302+ map . set ( [ "a" , "b" , "c" , "d" ] , 10 ) ;
303+ map . set ( [ "a" , "b" , "c" , "e" ] , 20 ) ;
304+ expect ( map . get ( [ "a" , "b" , "c" , "d" ] ) ) . toBe ( 10 ) ;
305+ expect ( map . get ( [ "a" , "b" , "c" , "e" ] ) ) . toBe ( 20 ) ;
306+
307+ // Delete one leaf value and ensure the other remains.
308+ expect ( map . delete ( [ "a" , "b" , "c" , "d" ] ) ) . toBe ( true ) ;
309+ let items = map . getAll ( [ "a" , "b" , "c" ] ) ;
310+ expect ( items ) . toContain ( 20 ) ;
311+ expect ( items ) . not . toContain ( 10 ) ;
312+
313+ // Delete the other leaf value; now the branch should be cleaned up.
314+ expect ( map . delete ( [ "a" , "b" , "c" , "e" ] ) ) . toBe ( true ) ;
315+ items = map . getAll ( [ "a" , "b" , "c" ] ) ;
316+ expect ( items ) . toEqual ( [ ] ) ;
317+ } ) ;
318+
319+ test ( "MultiLevelMap complex nested structure with interleaved keys" , ( ) => {
320+ const map = new Lang . MultiLevelMap < string > ( ) ;
321+ map . set ( [ "level1" , "a" , "x" ] , "ax" ) ;
322+ map . set ( [ "level1" , "a" , "y" ] , "ay" ) ;
323+ map . set ( [ "level1" , "b" ] , "b-main" ) ;
324+ map . set ( [ "level1" , "a" , "z" , "nested" ] , "az-nested" ) ;
325+
326+ // Direct retrievals.
327+ expect ( map . get ( [ "level1" , "b" ] ) ) . toBe ( "b-main" ) ;
328+ expect ( map . get ( [ "level1" , "a" , "x" ] ) ) . toBe ( "ax" ) ;
329+ expect ( map . get ( [ "level1" , "a" , "z" , "nested" ] ) ) . toBe ( "az-nested" ) ;
330+
331+ // getAll at the top level.
332+ const all = map . getAll ( [ "level1" ] ) ;
333+ expect ( all . sort ( ) ) . toEqual ( [ "ax" , "ay" , "b-main" , "az-nested" ] . sort ( ) ) ;
334+
335+ // getAll for a specific branch.
336+ const aBranch = map . getAll ( [ "level1" , "a" ] ) ;
337+ expect ( aBranch . sort ( ) ) . toEqual ( [ "ax" , "ay" , "az-nested" ] . sort ( ) ) ;
338+ } ) ;
339+
340+ test ( "MultiLevelMap non-existent keys behavior" , ( ) => {
341+ const map = new Lang . MultiLevelMap < number > ( ) ;
342+ // Retrieval on a key path that doesn't exist returns undefined.
343+ expect ( map . get ( [ "non" , "existent" ] ) ) . toBeUndefined ( ) ;
344+ // getAll should return an empty array when no branch exists.
345+ expect ( map . getAll ( [ "non" ] ) ) . toEqual ( [ ] ) ;
346+ // Deleting a non-existent key path returns false.
347+ expect ( map . delete ( [ "non" , "existent" ] ) ) . toBe ( false ) ;
348+ } ) ;
349+
350+ test ( "MapWithKeyFn basic set and get" , ( ) => {
351+ type Item = { id : number ; name : string } ;
352+ const keyFn = ( item : Item ) => item . id . toString ( ) ;
353+ const map = new Lang . MapWithKeyFn < Item , string > ( [ ] , keyFn ) ;
354+ const item1 : Item = { id : 1 , name : "Alice" } ;
355+ const item2 : Item = { id : 2 , name : "Bob" } ;
356+
357+ // Initially, get should return undefined and has should return false.
358+ expect ( map . get ( item1 ) ) . toBeUndefined ( ) ;
359+ expect ( map . has ( item2 ) ) . toBe ( false ) ;
360+
361+ // Set values.
362+ map . set ( item1 , "value1" ) ;
363+ map . set ( item2 , "value2" ) ;
364+
365+ expect ( map . get ( item1 ) ) . toBe ( "value1" ) ;
366+ expect ( map . get ( item2 ) ) . toBe ( "value2" ) ;
367+ expect ( map . has ( item1 ) ) . toBe ( true ) ;
368+ expect ( map . has ( item2 ) ) . toBe ( true ) ;
369+ } ) ;
370+
371+ test ( "MapWithKeyFn update value for existing key" , ( ) => {
372+ type Item = { id : number ; name : string } ;
373+ const keyFn = ( item : Item ) => item . id . toString ( ) ;
374+ const map = new Lang . MapWithKeyFn < Item , string > ( [ ] , keyFn ) ;
375+ const original : Item = { id : 1 , name : "Alice" } ;
376+
377+ map . set ( original , "initial" ) ;
378+ expect ( map . get ( original ) ) . toBe ( "initial" ) ;
379+
380+ // Update using a different instance with the same key.
381+ const updated : Item = { id : 1 , name : "Alice Updated" } ;
382+ map . set ( updated , "updated" ) ;
383+ expect ( map . get ( original ) ) . toBe ( "updated" ) ;
384+ expect ( map . get ( updated ) ) . toBe ( "updated" ) ;
385+ } ) ;
386+
387+ test ( "MapWithKeyFn iteration and clear" , ( ) => {
388+ type Item = { id : number ; name : string } ;
389+ const keyFn = ( item : Item ) => item . id . toString ( ) ;
390+ const items : Item [ ] = [
391+ { id : 1 , name : "Alice" } ,
392+ { id : 2 , name : "Bob" } ,
393+ { id : 3 , name : "Charlie" } ,
394+ ] ;
395+ const map = new Lang . MapWithKeyFn < Item , string > ( [ ] , keyFn ) ;
396+ items . forEach ( ( item , idx ) => map . set ( item , `value${ idx + 1 } ` ) ) ;
397+
398+ // Test keys, values, and entries iteration.
399+ const keys = [ ...map . keys ( ) ] ;
400+ const values = [ ...map . values ( ) ] ;
401+ const entries = [ ...map . entries ( ) ] ;
402+
403+ expect ( keys ) . toHaveLength ( 3 ) ;
404+ expect ( values ) . toHaveLength ( 3 ) ;
405+ expect ( entries ) . toHaveLength ( 3 ) ;
406+
407+ // Iterating over the map itself should yield the same entries.
408+ expect ( [ ...map ] ) . toEqual ( entries ) ;
409+
410+ // Test deletion of a key.
411+ expect ( map . delete ( items [ 0 ] ) ) . toBe ( true ) ;
412+ expect ( map . get ( items [ 0 ] ) ) . toBeUndefined ( ) ;
413+
414+ // Clear the map.
415+ map . clear ( ) ;
416+ expect ( map . size ) . toBe ( 0 ) ;
417+ } ) ;
418+
419+ test ( "MapWithKeyFn duplicate keys handling" , ( ) => {
420+ type User = { id : number ; username : string } ;
421+ const keyFn = ( user : User ) => user . id . toString ( ) ;
422+
423+ // Two separate objects with the same id should be treated as the same key.
424+ const user1 : User = { id : 1 , username : "alice" } ;
425+ const userDuplicate : User = { id : 1 , username : "aliceClone" } ;
426+ const user2 : User = { id : 2 , username : "bob" } ;
427+
428+ const map = new Lang . MapWithKeyFn < User , string > ( [ ] , keyFn ) ;
429+ map . set ( user1 , "first" ) ;
430+ // Setting a duplicate should overwrite the previous value.
431+ map . set ( userDuplicate , "updated" ) ;
432+
433+ expect ( map . get ( user1 ) ) . toBe ( "updated" ) ;
434+ expect ( map . get ( userDuplicate ) ) . toBe ( "updated" ) ;
435+ expect ( map . has ( user1 ) ) . toBe ( true ) ;
436+
437+ // Insert another distinct element.
438+ map . set ( user2 , "second" ) ;
439+ expect ( map . get ( user2 ) ) . toBe ( "second" ) ;
440+
441+ // Confirm iteration reflects unique keys.
442+ const entries = [ ...map . entries ( ) ] ;
443+ expect ( entries . length ) . toBe ( 2 ) ;
444+ } ) ;
0 commit comments