Skip to content

Commit e680b6a

Browse files
committed
More testing
1 parent cc6f3be commit e680b6a

File tree

4 files changed

+281
-13
lines changed

4 files changed

+281
-13
lines changed

modules/yup_python/bindings/yup_YupDataModel_bindings.cpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,7 @@ void registerYupDataModelBindings (py::module_& m)
9999

100100
py::class_<DataTree> classDataTree (m, "DataTree");
101101

102-
py::class_<DataTree::Iterator> classDataTreeIterator (classDataTree, "Iterator");
103-
104-
classDataTreeIterator
105-
.def (py::init<>())
106-
.def ("__iter__", [] (DataTree::Iterator& self) { return self; })
107-
.def ("__next__", [] (DataTree::Iterator& self)
108-
{
109-
// We need to manually implement the iteration logic
110-
// This is a simplified version - a proper implementation would track the end
111-
auto value = *self;
112-
++self;
113-
return value;
114-
});
102+
// Note: Iterator is bound but we primarily use __iter__ on DataTree itself for Python iteration
115103

116104
py::class_<DataTree::Transaction> classDataTreeTransaction (classDataTree, "Transaction");
117105

python/tests/test_yup_data_model/test_DataTree.py

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

python/tests/test_yup_data_model/test_Integration.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,13 @@ def test_move_child_with_undo():
298298
assert parent.getChild(0).getType() == yup.Identifier("Third")
299299
assert parent.getChild(1).getType() == yup.Identifier("Second")
300300
assert parent.getChild(2).getType() == yup.Identifier("First")
301+
302+
#==================================================================================================
303+
304+
def test_DataTreeListener_repr():
305+
"""Test DataTreeListener has proper type representation."""
306+
listener = DataTreeChangeCounter()
307+
308+
# Verify we can get the type name
309+
type_name = type(listener).__name__
310+
assert type_name is not None # Should have a valid type name

python/tests/test_yup_data_model/test_UndoManager.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,34 @@ def test_UndoManager_transaction_names():
250250
# Get transaction name
251251
name = manager.getCurrentTransactionName()
252252
assert isinstance(name, str)
253+
254+
#==================================================================================================
255+
256+
def test_UndoManager_repr():
257+
"""Test UndoManager has proper type representation."""
258+
manager = yup.UndoManager()
259+
260+
# Verify we can get the type name
261+
type_name = type(manager).__name__
262+
assert "UndoManager" in type_name
263+
264+
#==================================================================================================
265+
266+
def test_UndoManager_ScopedTransaction_repr():
267+
"""Test UndoManager.ScopedTransaction has proper type representation."""
268+
manager = yup.UndoManager()
269+
scoped = yup.UndoManager.ScopedTransaction(manager, "Test Transaction")
270+
271+
# Verify we can get the type name
272+
type_name = type(scoped).__name__
273+
assert "ScopedTransaction" in type_name
274+
275+
#==================================================================================================
276+
277+
def test_UndoableAction_repr():
278+
"""Test UndoableAction has proper type representation."""
279+
action = UndoableActionImpl()
280+
281+
# Verify we can get the type name
282+
type_name = type(action).__name__
283+
assert type_name is not None # Should have a valid type name

0 commit comments

Comments
 (0)