@@ -291,3 +291,242 @@ def test_DataTree_getChildWithName():
291291 # Non-existent child
292292 nonExistent = parent .getChildWithName (yup .Identifier ("NonExistent" ))
293293 assert not nonExistent .isValid ()
294+
295+ #==================================================================================================
296+
297+ def test_DataTree_forEachChild_with_bool_return ():
298+ """Test forEachChild with bool return for early exit."""
299+ parent = yup .DataTree (yup .Identifier ("Parent" ))
300+
301+ transaction = parent .beginTransaction ()
302+ for i in range (5 ):
303+ child = yup .DataTree (yup .Identifier (f"Child{ i } " ))
304+ transaction .addChild (child )
305+ transaction .commit ()
306+
307+ # Test early exit when callback returns True
308+ count = 0
309+ def callback_early_exit (child ):
310+ nonlocal count
311+ count += 1
312+ # Stop after processing 2 children
313+ return count >= 2
314+
315+ parent .forEachChild (callback_early_exit )
316+ assert count == 2 # Should stop early
317+
318+ # Test normal iteration when callback returns False
319+ count2 = 0
320+ def callback_no_exit (child ):
321+ nonlocal count2
322+ count2 += 1
323+ return False # Continue iteration
324+
325+ parent .forEachChild (callback_no_exit )
326+ assert count2 == 5 # Should process all children
327+
328+ #==================================================================================================
329+
330+ def test_DataTree_forEachDescendant ():
331+ """Test forEachDescendant method."""
332+ root = yup .DataTree (yup .Identifier ("Root" ))
333+
334+ # Build a hierarchy
335+ transaction = root .beginTransaction ()
336+ child1 = yup .DataTree (yup .Identifier ("Child1" ))
337+ child2 = yup .DataTree (yup .Identifier ("Child2" ))
338+ transaction .addChild (child1 )
339+ transaction .addChild (child2 )
340+ transaction .commit ()
341+
342+ actualChild1 = root .getChild (0 )
343+ transaction2 = actualChild1 .beginTransaction ()
344+ grandchild1 = yup .DataTree (yup .Identifier ("Grandchild1" ))
345+ grandchild2 = yup .DataTree (yup .Identifier ("Grandchild2" ))
346+ transaction2 .addChild (grandchild1 )
347+ transaction2 .addChild (grandchild2 )
348+ transaction2 .commit ()
349+
350+ # Test callback visits all descendants
351+ visited = []
352+ def callback (child ):
353+ visited .append (child .getType ().toString ())
354+ return False
355+
356+ root .forEachDescendant (callback )
357+ assert len (visited ) == 4 # 2 children + 2 grandchildren
358+ assert "Child1" in visited
359+ assert "Child2" in visited
360+ assert "Grandchild1" in visited
361+ assert "Grandchild2" in visited
362+
363+ #==================================================================================================
364+
365+ def test_DataTree_forEachDescendant_with_bool_return ():
366+ """Test forEachDescendant with bool return for early exit."""
367+ root = yup .DataTree (yup .Identifier ("Root" ))
368+
369+ # Build a hierarchy
370+ transaction = root .beginTransaction ()
371+ for i in range (3 ):
372+ child = yup .DataTree (yup .Identifier (f"Child{ i } " ))
373+ transaction .addChild (child )
374+ transaction .commit ()
375+
376+ # Add grandchildren to first child
377+ actualChild = root .getChild (0 )
378+ transaction2 = actualChild .beginTransaction ()
379+ for i in range (3 ):
380+ grandchild = yup .DataTree (yup .Identifier (f"Grandchild{ i } " ))
381+ transaction2 .addChild (grandchild )
382+ transaction2 .commit ()
383+
384+ # Test early exit
385+ count = 0
386+ def callback_early_exit (child ):
387+ nonlocal count
388+ count += 1
389+ return count >= 2 # Stop after 2 descendants
390+
391+ root .forEachDescendant (callback_early_exit )
392+ assert count == 2 # Should stop early
393+
394+ #==================================================================================================
395+
396+ def test_DataTree_findChildren ():
397+ """Test findChildren with predicate."""
398+ parent = yup .DataTree (yup .Identifier ("Parent" ))
399+
400+ transaction = parent .beginTransaction ()
401+ for i in range (5 ):
402+ child = yup .DataTree (yup .Identifier (f"Item{ i } " ))
403+ transaction .setProperty (yup .Identifier ("index" ), i )
404+ transaction .addChild (child )
405+ transaction .commit ()
406+
407+ # Add a property to some children
408+ for i in [0 , 2 , 4 ]:
409+ actualChild = parent .getChild (i )
410+ trans = actualChild .beginTransaction ()
411+ trans .setProperty (yup .Identifier ("even" ), True )
412+ trans .commit ()
413+
414+ # Find children with even property
415+ found = parent .findChildren (lambda c : c .hasProperty (yup .Identifier ("even" )))
416+ assert len (found ) == 3
417+ assert all (child .hasProperty (yup .Identifier ("even" )) for child in found )
418+
419+ # Find children by name pattern
420+ found2 = parent .findChildren (lambda c : c .getType () == yup .Identifier ("Item2" ))
421+ assert len (found2 ) == 1
422+ assert found2 [0 ].getType () == yup .Identifier ("Item2" )
423+
424+ #==================================================================================================
425+
426+ def test_DataTree_findDescendants ():
427+ """Test findDescendants with predicate."""
428+ root = yup .DataTree (yup .Identifier ("Root" ))
429+
430+ # Build hierarchy
431+ transaction = root .beginTransaction ()
432+ child1 = yup .DataTree (yup .Identifier ("Child1" ))
433+ child2 = yup .DataTree (yup .Identifier ("Child2" ))
434+ transaction .addChild (child1 )
435+ transaction .addChild (child2 )
436+ transaction .commit ()
437+
438+ # Add grandchildren
439+ actualChild1 = root .getChild (0 )
440+ transaction2 = actualChild1 .beginTransaction ()
441+ grandchild1 = yup .DataTree (yup .Identifier ("Target" ))
442+ grandchild2 = yup .DataTree (yup .Identifier ("Other" ))
443+ transaction2 .addChild (grandchild1 )
444+ transaction2 .addChild (grandchild2 )
445+ transaction2 .commit ()
446+
447+ actualChild2 = root .getChild (1 )
448+ transaction3 = actualChild2 .beginTransaction ()
449+ grandchild3 = yup .DataTree (yup .Identifier ("Target" ))
450+ transaction3 .addChild (grandchild3 )
451+ transaction3 .commit ()
452+
453+ # Find all descendants named "Target"
454+ found = root .findDescendants (lambda d : d .getType () == yup .Identifier ("Target" ))
455+ assert len (found ) == 2
456+ assert all (d .getType () == yup .Identifier ("Target" ) for d in found )
457+
458+ #==================================================================================================
459+
460+ def test_DataTree_findDescendant ():
461+ """Test findDescendant with predicate (finds first match)."""
462+ root = yup .DataTree (yup .Identifier ("Root" ))
463+
464+ # Build hierarchy
465+ transaction = root .beginTransaction ()
466+ child1 = yup .DataTree (yup .Identifier ("Child1" ))
467+ child2 = yup .DataTree (yup .Identifier ("Child2" ))
468+ transaction .addChild (child1 )
469+ transaction .addChild (child2 )
470+ transaction .commit ()
471+
472+ # Add grandchildren
473+ actualChild1 = root .getChild (0 )
474+ transaction2 = actualChild1 .beginTransaction ()
475+ grandchild1 = yup .DataTree (yup .Identifier ("Target" ))
476+ transaction2 .addChild (grandchild1 )
477+ transaction2 .commit ()
478+
479+ actualChild2 = root .getChild (1 )
480+ transaction3 = actualChild2 .beginTransaction ()
481+ grandchild2 = yup .DataTree (yup .Identifier ("Target" ))
482+ transaction3 .addChild (grandchild2 )
483+ transaction3 .commit ()
484+
485+ # Find first descendant named "Target"
486+ found = root .findDescendant (lambda d : d .getType () == yup .Identifier ("Target" ))
487+ assert found .isValid ()
488+ assert found .getType () == yup .Identifier ("Target" )
489+
490+ # Find non-existent descendant
491+ notFound = root .findDescendant (lambda d : d .getType () == yup .Identifier ("NonExistent" ))
492+ assert not notFound .isValid ()
493+
494+ #==================================================================================================
495+
496+ def test_DataTree_repr ():
497+ """Test DataTree __repr__ method."""
498+ tree = yup .DataTree (yup .Identifier ("Settings" ))
499+ repr_str = repr (tree )
500+
501+ # Should contain class name and type
502+ assert "DataTree" in repr_str
503+ assert "Settings" in repr_str
504+ assert "object at" in repr_str
505+
506+ # Invalid tree repr
507+ invalid_tree = yup .DataTree ()
508+ invalid_repr = repr (invalid_tree )
509+ assert "DataTree" in invalid_repr
510+
511+ #==================================================================================================
512+
513+ def test_DataTree_Transaction_repr ():
514+ """Test DataTree.Transaction has proper type representation."""
515+ tree = yup .DataTree (yup .Identifier ("Test" ))
516+ transaction = tree .beginTransaction ()
517+
518+ # Verify we can get the type name
519+ type_name = type (transaction ).__name__
520+ assert "Transaction" in type_name
521+
522+ #==================================================================================================
523+
524+ def test_DataTree_ValidatedTransaction_type ():
525+ """Test DataTree.ValidatedTransaction has proper type representation."""
526+ tree = yup .DataTree (yup .Identifier ("Test" ))
527+ transaction = tree .beginTransaction ()
528+
529+ # ValidatedTransaction is obtained through validation
530+ # For now, just verify the type exists and is accessible
531+ type_name = type (transaction ).__name__
532+ assert type_name is not None
0 commit comments