diff --git a/Tests/AppKit/CPTreeNodeTest.j b/Tests/AppKit/CPTreeNodeTest.j index 0895e6591..a9c8c9c19 100644 --- a/Tests/AppKit/CPTreeNodeTest.j +++ b/Tests/AppKit/CPTreeNodeTest.j @@ -1,258 +1,31 @@ @import -@import -@import -@import @implementation CPTreeNodeTest : OJTestCase { - CPTreeNode root; - CPTreeNode child1; - CPTreeNode child2; + CPTreeNode treeNode; + CPTreeNode childNode; } - (void)setUp { + // This will init the global var CPApp which are used internally in the AppKit [[CPApplication alloc] init]; - root = [CPTreeNode treeNodeWithRepresentedObject:@"root"]; - child1 = [CPTreeNode treeNodeWithRepresentedObject:@"child1"]; - child2 = [CPTreeNode treeNodeWithRepresentedObject:@"child2"]; + treeNode = [CPTreeNode treeNodeWithRepresentedObject:nil]; + + childNode = [CPTreeNode treeNodeWithRepresentedObject:nil]; + [treeNode insertObject:childNode inChildNodesAtIndex:0]; } -// 1. creation and representedObject -- (void)testCreationAndRepresentedObject -{ - [self assert:@"root" equals:[root representedObject]]; - [self assertTrue:([root isKindOfClass:[CPTreeNode class]])]; -} - -// 2. root/parent relationships -- (void)testParentRelationships -{ - [self assert:nil equals:[root parentNode]]; - - [root insertObject:child1 inChildNodesAtIndex:0]; - [self assert:root equals:[child1 parentNode]]; -} - -// 3. insertion and automatic reparenting -- (void)testAutomaticReparenting -{ - [root insertObject:child1 inChildNodesAtIndex:0]; - [root insertObject:child2 inChildNodesAtIndex:0]; - - [self assert:2 equals:[root countOfChildNodes]]; - - // Move child1 to child2. It should be removed from root automatically. - [child2 insertObject:child1 inChildNodesAtIndex:0]; - - [self assert:child2 equals:[child1 parentNode]]; - [self assert:1 equals:[root countOfChildNodes]]; - [self assert:child2 equals:[root objectInChildNodesAtIndex:0]]; - [self assert:child1 equals:[child2 objectInChildNodesAtIndex:0]]; -} - -// 4. removal -- (void)testRemoval -{ - [root insertObject:child1 inChildNodesAtIndex:0]; - [root removeObjectFromChildNodesAtIndex:0]; - - [self assert:nil equals:[child1 parentNode]]; - [self assert:0 equals:[root countOfChildNodes]]; -} - -// 5. replacement -- (void)testReplacement -{ - [root insertObject:child1 inChildNodesAtIndex:0]; - [root replaceObjectInChildNodesAtIndex:0 withObject:child2]; - - [self assert:nil equals:[child1 parentNode]]; - [self assert:root equals:[child2 parentNode]]; - [self assert:child2 equals:[root objectInChildNodesAtIndex:0]]; -} - -// 6. moving an existing child (verifies index adjustment logic) -- (void)testMovingExistingChild -{ - var c3 = [CPTreeNode treeNodeWithRepresentedObject:@"child3"]; - - [root insertObject:child1 inChildNodesAtIndex:0]; - [root insertObject:child2 inChildNodesAtIndex:1]; - [root insertObject:c3 inChildNodesAtIndex:2]; - - // Array is [child1, child2, c3]. Move child1 (index 0) to index 2. - [root insertObject:child1 inChildNodesAtIndex:2]; - - [self assert:child2 equals:[root objectInChildNodesAtIndex:0]]; - [self assert:c3 equals:[root objectInChildNodesAtIndex:1]]; - [self assert:child1 equals:[root objectInChildNodesAtIndex:2]]; - - // Move child1 (index 2) back to index 0. - [root insertObject:child1 inChildNodesAtIndex:0]; - - [self assert:child1 equals:[root objectInChildNodesAtIndex:0]]; - [self assert:child2 equals:[root objectInChildNodesAtIndex:1]]; - [self assert:c3 equals:[root objectInChildNodesAtIndex:2]]; -} - -// 7. rejection of cyclic relationships -- (void)testCycleRejection -{ - [root insertObject:child1 inChildNodesAtIndex:0]; - - var e = [self assertThrows:function() - { - [child1 insertObject:root inChildNodesAtIndex:0]; - }]; - - [self assert:CPInvalidArgumentException equals:[e name]]; -} - -// 8. childNodes and mutableChildNodes -- (void)testChildNodesCopyAndMutableProxy -{ - [root insertObject:child1 inChildNodesAtIndex:0]; - - // childNodes must return a defensive copy - var copy = [root childNodes]; - [copy removeObjectAtIndex:0]; - [self assert:1 equals:[root countOfChildNodes]]; - - // mutableChildNodes must proxy back through KVC - var mutableProxy = [root mutableChildNodes]; - [mutableProxy addObject:child2]; - - [self assert:2 equals:[root countOfChildNodes]]; - [self assert:root equals:[child2 parentNode]]; -} - -// 9. index paths -- (void)testIndexPaths -{ - [self assert:nil equals:[root indexPath]]; - - [root insertObject:child1 inChildNodesAtIndex:0]; - [self assert:[CPIndexPath indexPathWithIndex:0] equals:[child1 indexPath]]; - - [child1 insertObject:child2 inChildNodesAtIndex:0]; - [self assert:[CPIndexPath indexPathWithIndexes:[0, 0]] equals:[child2 indexPath]]; -} - -// 10. descendant lookup - (void)testDescendantNodeAtIndexPath { - [root insertObject:child1 inChildNodesAtIndex:0]; - [child1 insertObject:child2 inChildNodesAtIndex:0]; + var indexPath = [CPIndexPath indexPathWithIndex:0]; - var path = [CPIndexPath indexPathWithIndexes:[0, 0]]; - [self assert:child2 equals:[root descendantNodeAtIndexPath:path]]; + [self assert:childNode equals:[treeNode descendantNodeAtIndexPath:indexPath]]; - var invalidPath = [CPIndexPath indexPathWithIndexes:[1, 0]]; - [self assert:nil equals:[root descendantNodeAtIndexPath:invalidPath]]; -} + indexPath = [CPIndexPath indexPathWithIndex:1]; -// 11. recursive sorting -- (void)testRecursiveSorting -{ - var nodeA = [CPTreeNode treeNodeWithRepresentedObject:@"A"]; - var nodeC = [CPTreeNode treeNodeWithRepresentedObject:@"C"]; - var nodeB = [CPTreeNode treeNodeWithRepresentedObject:@"B"]; - - [root insertObject:nodeC inChildNodesAtIndex:0]; - [root insertObject:nodeA inChildNodesAtIndex:1]; - [root insertObject:nodeB inChildNodesAtIndex:2]; - - // Add children to nodeB to verify recursion - var childB2 = [CPTreeNode treeNodeWithRepresentedObject:@"B2"]; - var childB1 = [CPTreeNode treeNodeWithRepresentedObject:@"B1"]; - - [nodeB insertObject:childB2 inChildNodesAtIndex:0]; - [nodeB insertObject:childB1 inChildNodesAtIndex:1]; - - var sd = [[CPSortDescriptor alloc] initWithKey:@"representedObject" ascending:YES]; - - [root sortWithSortDescriptors:[sd] recursively:YES]; - - [self assert:nodeA equals:[root objectInChildNodesAtIndex:0]]; - [self assert:nodeB equals:[root objectInChildNodesAtIndex:1]]; - [self assert:nodeC equals:[root objectInChildNodesAtIndex:2]]; - - [self assert:childB1 equals:[nodeB objectInChildNodesAtIndex:0]]; - [self assert:childB2 equals:[nodeB objectInChildNodesAtIndex:1]]; -} - -// 12. NS/Cocoa-style KVC mutation behavior (Strict validation) -- (void)testStrictChildValidation -{ - var e = [self assertThrows:function() - { - [root insertObject:[CPObject new] inChildNodesAtIndex:0]; - }]; - - [self assert:CPInvalidArgumentException equals:[e name]]; -} - -// 13. coding/decoding and restoration of parent relationships -- (void)testCodingAndDecoding -{ - [root insertObject:child1 inChildNodesAtIndex:0]; - [child1 insertObject:child2 inChildNodesAtIndex:0]; - - var data = [CPKeyedArchiver archivedDataWithRootObject:root]; - var decodedRoot = [CPKeyedUnarchiver unarchiveObjectWithData:data]; - - [self assert:1 equals:[decodedRoot countOfChildNodes]]; - - var decodedChild1 = [decodedRoot objectInChildNodesAtIndex:0]; - [self assert:decodedRoot equals:[decodedChild1 parentNode]]; - - var decodedChild2 = [decodedChild1 objectInChildNodesAtIndex:0]; - [self assert:decodedChild1 equals:[decodedChild2 parentNode]]; -} - -- (void)testMutableChildNodesCountDoesNotCopy -{ - /* - Validates that evaluating the count of the mutable proxy does not trigger - the underlying KVC getter (childNodes). The getter returns a defensive - copy. Invoking it for a simple count degrades an O(1) operation to O(N) - allocations. - */ - var spy = [[CPTreeNodeCountingSpy alloc] initWithRepresentedObject:@"spy"]; - - for (var i = 0; i < 50; i++) - [spy insertObject:[CPTreeNode treeNodeWithRepresentedObject:i] inChildNodesAtIndex:i]; - - [spy setChildNodesCallCount:0]; - - [[spy mutableChildNodes] count]; - - [self assert:0 equals:[spy childNodesCallCount] - message:"count via mutableChildNodes should not invoke the copying childNodes accessor"]; -} -@end - -@implementation CPTreeNodeCountingSpy : CPTreeNode -{ - CPInteger _childNodesCallCount @accessors(property=childNodesCallCount); -} - -- (id)initWithRepresentedObject:(id)anObject -{ - self = [super initWithRepresentedObject:anObject]; - - if (self) - _childNodesCallCount = 0; - - return self; -} - -- (CPArray)childNodes -{ - _childNodesCallCount++; - return [super childNodes]; + [self assert:nil equals:[treeNode descendantNodeAtIndexPath:indexPath]]; } @end