<?php
/*
 * This file is part of the sfPropelActAsNestedSetBehavior package.
 * 
 * (c) 2007 Tristan Rivoallan <tristan@rivoallan.net>
 * 
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * Unit tests for the sfPropelActAsNestedSetBehavior plugin.
 *
 * Despite running unit tests, we use the functional tests bootstrap to take advantage of propel
 * classes autoloading...
 * 
 * In order to run the tests in your context, you have to copy this file in a symfony test directory
 * and configure it appropriately (see the "configuration" section at the beginning of the file)
 *  
 * @author   Tristan Rivoallan <tristan@rivoallan.net>
 */

// configuration
// -- an existing application name
$app = 'testapp';

// -- the model class the tests should use
define('NESTEDSETS_CLASS', 'Post');

// -- path to the symfony project where the plugin resides
$sf_path = '/home/trivoallan/workspace/nestedset-testapp';
 
// bootstrap
include($sf_path . '/test/bootstrap/functional.php');

// create a new test browser
$browser = new sfTestBrowser();
$browser->initialize();

// initialize database manager
$databaseManager = new sfDatabaseManager();
$databaseManager->initialize();

$con = Propel::getConnection();

// cleanup database
call_user_func(array(_create_node()->getPeer(), 'doDeleteAll'));

// getStubFromPeer
$t = new lime_test(6, new lime_output_color());
$t->diag('getStubFromPeer');
$t->is(sfPropelActAsNestedSetBehavior::getStubFromPeer('PeerKategorijePeer'), 'PeerKategorije',
       'getStubFromPeer() returns correct stub name');

// makeRoot = new lime_test(4, new lime_output_color());
$t->diag('makeRoot');

$root = _create_node();
$root->makeRoot();
$root->save();

$t->is($root->getLeftValue(), 1, 'ROOT "left value" is "1"');
$t->is($root->getRightValue(), 2, 'ROOT "right value" is "2"');
$t->is($root->getParentIdValue(), null, 'ROOT "parent id" is "null"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');

$p = _create_node();
$p->setLeftValue(2);
$p->setRightValue(3);
$p->save();

try
{
  $p->makeRoot();
  $t->fail('makeRoot() throws an exception when trying to turn an existing node into a root node');
}
catch (Exception $e)
{
  $t->pass('makeRoot() throws an exception when trying to turn an existing node into a root node');
}

$p->delete();

// insertAsFirstChildOf
$t = new lime_test(8, new lime_output_color());
$t->diag('insertAsFirstChildOf');
$t->diag('insert N1 as first child of ROOT');

$t->diag('root');
$t->diag(' |-N1');
$n1 = _create_node();
$n1->insertAsFirstChildOf($root);
$n1->save();
$root->reload();
$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 4, 'root "right" is "4"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 2, 'N1 "left" is "2"');
$t->is($n1->getRightValue(), 3, 'N1 "right" is "3"');
$t->is($n1->getParentIdValue(), $root->getId(), 'N1 parent id equals ROOT id');
$t->is($n1->getScopeIdValue(), $root->getScopeIdValue(), 'N1 scope id equals ROOT id');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');

// isEqualTo
$t = new lime_test(2, new lime_output_color());
$t->is($n1->isEqualTo($n1), true, 'isEqualTo() returns true when nodes are equivalent');
$t->is($root->isEqualTo($n1), false, 'isEqualTo() returns false when nodes are different');

$t = new lime_test(25, new lime_output_color());
$t->diag('insert N2 as first child of ROOT');
$t->diag('root');
$t->diag(' |-N2');
$t->diag(' |-N1');

$n2 = _create_node();
$n2->insertAsFirstChildOf($root, $con);
$n2->save();

$n1 = $n1->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 6, 'root "right" is "6"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 4, 'N1 "left" is "4"');
$t->is($n1->getRightValue(), 5, 'N1 "right" is "5"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 2, 'N2 "left" is "2"');
$t->is($n2->getRightValue(), 3, 'N2 "right" is "3"');
$t->is($n2->getParentIdValue(), $root->getId(), 'N2 parent id equals ROOT id');
$t->is($n2->getScopeIdValue(), $root->getScopeIdValue(), 'N2 scope id equals ROOT id');
$t->is($n2->getLevel(), 1, 'N2 "level" is "1"');

$t->diag('insert N3 as first child of N2');
$t->diag('root');
$t->diag(' |-N2');
$t->diag('   |-N3');
$t->diag(' |-N1');

$n3 = _create_node();
$n3->insertAsFirstChildOf($n2);
$n3->save();
$n1 = $n1->reload();
$n2 = $n2->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 8, 'root "right" is "8"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 6, 'N1 "left" is "6"');
$t->is($n1->getRightValue(), 7, 'N1 "right" is "7"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 2, 'N2 "left" is "2"');
$t->is($n2->getRightValue(), 5, 'N2 "right" is "5"');
$t->is($n2->getLevel(), 1, 'N2 "level" is "1"');
$t->is($n3->getLeftValue(), 3, 'N3 "left" is "3"');
$t->is($n3->getRightValue(), 4, 'N3 "right" is "4"');
$t->is($n3->getParentIdValue(), $n2->getId(), 'N3 parent id equals N2 id');
$t->is($n3->getScopeIdValue(), $root->getScopeIdValue(), 'N3 scope id equals ROOT id');
$t->is($n3->getLevel(), 2, 'N3 "level" is "2"');

// insertAsLastChildOf
$t = new lime_test(37, new lime_output_color());
$t->diag('insertAsLastChildOf');
$t->diag('insert N4 as last child of N2');
$t->diag('root');
$t->diag(' |-N2');
$t->diag('   |-N3');
$t->diag('   |-N4');
$t->diag(' |-N1');

$n4 = _create_node();
$n4->insertAsLastChildOf($n2);
$n4->save();

// -- reload nodes
$n1 = $n1->reload();
$n2 = $n2->reload();
$n3 = $n3->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 10, 'root "right" is "10"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 8, 'N1 "left" is "8"');
$t->is($n1->getRightValue(), 9, 'N1 "right" is "9"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 2, 'N2 "left" is "2"');
$t->is($n2->getRightValue(), 7, 'N2 "right" is "7"');
$t->is($n2->getLevel(), 1, 'N2 "level" is "1"');
$t->is($n3->getLeftValue(), 3, 'N3 "left" is "3"');
$t->is($n3->getRightValue(), 4, 'N3 "right" is "4"');
$t->is($n3->getLevel(), 2, 'N3 "level" is "2"');
$t->is($n4->getLeftValue(), 5, 'N4 "left" is "5"');
$t->is($n4->getRightValue(), 6, 'N4 "right" is "6"');
$t->is($n4->getLevel(), 2, 'N4 "level" is "2"');
$t->is($n4->getParentIdValue(), $n2->getId(), 'N4 parent id equals N2 id');
$t->is($n4->getScopeIdValue(), $root->getScopeIdValue(), 'N4 scope id equals ROOT id');

$t->diag('insert N5 as last child of ROOT');
$t->diag('root');
$t->diag(' |-N2');
$t->diag('   |-N3');
$t->diag('   |-N4');
$t->diag(' |-N1');
$t->diag(' |-N5');

$n5 = _create_node();
$n5->insertAsLastChildOf($root);
$n5->save();

// -- reload nodes
$n1 = $n1->reload();
$n2 = $n2->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 12, 'root "right" is "12"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 8, 'N1 "left" is "8"');
$t->is($n1->getRightValue(), 9, 'N1 "right" is "9"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 2, 'N2 "left" is "2"');
$t->is($n2->getRightValue(), 7, 'N2 "right" is "7"');
$t->is($n2->getLevel(), 1, 'N2 "level" is "1"');
$t->is($n3->getLeftValue(), 3, 'N3 "left" is "3"');
$t->is($n3->getRightValue(), 4, 'N3 "right" is "4"');
$t->is($n3->getLevel(), 2, 'N3 "level" is "2"');
$t->is($n4->getLeftValue(), 5, 'N4 "left" is "5"');
$t->is($n4->getRightValue(), 6, 'N4 "right" is "6"');
$t->is($n4->getLevel(), 2, 'N4 "level" is "2"');
$t->is($n5->getLeftValue(), 10, 'N5 "left" is "10"');
$t->is($n5->getRightValue(), 11, 'N5 "right" is "11"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n5->getParentIdValue(), $root->getId(), 'N3 parent id equals ROOT id');
$t->is($n5->getScopeIdValue(), $root->getScopeIdValue(), 'N3 scope id equals ROOT id');

// insertAsNextSiblingOf
$t = new lime_test(50, new lime_output_color());
$t->diag('insertAsNextSiblingOf');
$t->diag('insert N6 as next sibling N2');
$t->diag('root');
$t->diag(' |-N2');
$t->diag('   |-N3');
$t->diag('   |-N4');
$t->diag(' |-N6');
$t->diag(' |-N1');
$t->diag(' |-N5');

$n6 = _create_node();
$n6->insertAsNextSiblingOf($n2);
$n6->save();

// -- reload nodes
$n1 = $n1->reload();
$n2 = $n2->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 14, 'root "right" is "14"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 10, 'N1 "left" is "10"');
$t->is($n1->getRightValue(), 11, 'N1 "right" is "11"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 2, 'N2 "left" is "2"');
$t->is($n2->getRightValue(), 7, 'N2 "right" is "7"');
$t->is($n2->getLevel(), 1, 'N2 "level" is "1"');
$t->is($n3->getLeftValue(), 3, 'N3 "left" is "3"');
$t->is($n3->getRightValue(), 4, 'N3 "right" is "4"');
$t->is($n3->getLevel(), 2, 'N3 "level" is "2"');
$t->is($n4->getLeftValue(), 5, 'N4 "left" is "5"');
$t->is($n4->getRightValue(), 6, 'N4 "right" is "6"');
$t->is($n4->getLevel(), 2, 'N4 "level" is "2"');
$t->is($n5->getLeftValue(), 12, 'N5 "left" is "12"');
$t->is($n5->getRightValue(), 13, 'N5 "right" is "13"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n6->getLeftValue(), 8, 'N6 "left" is "8"');
$t->is($n6->getRightValue(), 9, 'N6 "right" is "9"');
$t->is($n6->getLevel(), 1, 'N6 "level" is "1"');
$t->is($n6->getParentIdValue(), $n2->getParentIdValue(), 'N6 parent id equals N2 parent id');
$t->is($n6->getScopeIdValue(), $n2->getScopeIdValue(), 'N6 scope id equals N2 scope id');

$t->diag('insert N7 as next sibling of N3');
$t->diag('root');
$t->diag(' |-N2');
$t->diag('   |-N3');
$t->diag('   |-N7');
$t->diag('   |-N4');
$t->diag(' |-N6');
$t->diag(' |-N1');
$t->diag(' |-N5');

$n7 = _create_node();
$n7->insertAsNextSiblingOf($n3);
$n7->save();

// -- reload nodes
$n1 = $n1->reload();
$n2 = $n2->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$n6 = $n6->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 16, 'root "right" is "16"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 12, 'N1 "left" is "12"');
$t->is($n1->getRightValue(), 13, 'N1 "right" is "13"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 2, 'N2 "left" is "2"');
$t->is($n2->getRightValue(), 9, 'N2 "right" is "9"');
$t->is($n2->getLevel(), 1, 'N2 "level" is "1"');
$t->is($n3->getLeftValue(), 3, 'N3 "left" is "3"');
$t->is($n3->getRightValue(), 4, 'N3 "right" is "4"');
$t->is($n3->getLevel(), 2, 'N3 "level" is "2"');
$t->is($n4->getLeftValue(), 7, 'N4 "left" is "7"');
$t->is($n4->getRightValue(), 8, 'N4 "right" is "8"');
$t->is($n4->getLevel(), 2, 'N4 "level" is "2"');
$t->is($n5->getLeftValue(), 14, 'N5 "left" is "14"');
$t->is($n5->getRightValue(), 15, 'N5 "right" is "15"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n6->getLeftValue(), 10, 'N6 "left" is "10"');
$t->is($n6->getRightValue(), 11, 'N6 "right" is "11"');
$t->is($n6->getLevel(), 1, 'N6 "level" is "1"');
$t->is($n7->getLeftValue(), 5, 'N7 "left" is "5"');
$t->is($n7->getRightValue(), 6, 'N7 "right" is "6"');
$t->is($n7->getLevel(), 2, 'N7 "level" is "2"');
$t->is($n7->getParentIdValue(), $n3->getParentIdValue(), 'N7 parent id equals N3 parent id');
$t->is($n7->getScopeIdValue(), $n3->getScopeIdValue(), 'N7 scope id equals N3 scope id');

try
{  
  $t->diag('insert N8 as next sibling of ROOT');
  $n8 = _create_node();
  $n8->insertAsNextSiblingOf($root);
  $n8->save();
  $n8->fail('insertAsNextSiblingOf throws an exception when trying to insert a sibling to a root node'); 
}
catch (Exception $e)
{
  $t->pass('insertAsNextSiblingOf throws an exception when trying to insert a sibling to a root node');
}

// insertAsPrevSiblingOf
$t = new lime_test(30, new lime_output_color());
$t->diag('insertAsPrevSiblingOf');
$t->diag('insert N8 as previous sibling of N1');
$t->diag('root');
$t->diag(' |-N2');
$t->diag('   |-N3');
$t->diag('   |-N7');
$t->diag('   |-N4');
$t->diag(' |-N6');
$t->diag(' |-N8');
$t->diag(' |-N1');
$t->diag(' |-N5');

$n8 = _create_node();
$n8->insertAsPrevSiblingOf($n1);
$n8->save();

// -- reload nodes
$n1 = $n1->reload();
$n2 = $n2->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$n6 = $n6->reload();
$n7 = $n7->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 18, 'root "right" is "18"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 14, 'N1 "left" is "14"');
$t->is($n1->getRightValue(), 15, 'N1 "right" is "15"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 2, 'N2 "left" is "2"');
$t->is($n2->getRightValue(), 9, 'N2 "right" is "9"');
$t->is($n2->getLevel(), 1, 'N2 "level" is "1"');
$t->is($n3->getLeftValue(), 3, 'N3 "left" is "3"');
$t->is($n3->getRightValue(), 4, 'N3 "right" is "4"');
$t->is($n3->getLevel(), 2, 'N3 "level" is "2"');
$t->is($n4->getLeftValue(), 7, 'N4 "left" is "7"');
$t->is($n4->getRightValue(), 8, 'N4 "right" is "8"');
$t->is($n4->getLevel(), 2, 'N4 "level" is "2"');
$t->is($n5->getLeftValue(), 16, 'N5 "left" is "16"');
$t->is($n5->getRightValue(), 17, 'N5 "right" is "17"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n6->getLeftValue(), 10, 'N6 "left" is "10"');
$t->is($n6->getRightValue(), 11, 'N6 "right" is "11"');
$t->is($n6->getLevel(), 1, 'N6 "level" is "1"');
$t->is($n7->getLeftValue(), 5, 'N7 "left" is "5"');
$t->is($n7->getRightValue(), 6, 'N7 "right" is "6"');
$t->is($n7->getLevel(), 2, 'N7 "level" is "2"');
$t->is($n8->getLeftValue(), 12, 'N8 "left" is "12"');
$t->is($n8->getRightValue(), 13, 'N8 "right" is "13"');
$t->is($n8->getLevel(), 1, 'N8 "level" is "1"');
$t->is($n8->getParentIdValue(), $n1->getParentIdValue(), 'N8 parent id equals N1 parent id');
$t->is($n8->getScopeIdValue(), $n1->getScopeIdValue(), 'N8 scope id equals N1 scope id');

try
{  
  $t->diag('insert N9 as previous sibling of ROOT');
  $n9 = _create_node();
  $n9->insertAsNextSiblingOf($root);
  $n9->save();
  $n9->fail('insertAsPrevSiblingOf throws an exception when trying to insert a sibling to a root node'); 
}
catch (Exception $e)
{
  $t->pass('insertAsPrevSiblingOf throws an exception when trying to insert a sibling to a root node');
}

// hasChildren()
$t = new lime_test(3, new lime_output_color());
$t->diag('hasChildren');
$t->ok($root->hasChildren(), 'root has children');
$t->ok($n2->hasChildren(), 'N2 has children');
$t->isnt($n6->hasChildren(), true, 'N6 does not have children');

// getChildren
$t = new lime_test(11, new lime_output_color());
$root = $root->reload();
$root_children = $root->getChildren();
$t->diag('getChildren');
$t->diag('Retrieving children of ROOT');
$t->is(count($root_children), 5, 'root node has "5 children"');
foreach ($root_children as $child)
{
  $t->is($child->getLevel(), 1, 'root child "level" is "1"');
}

$t->diag('Retrieving children of N2');
$n2 = $n2->reload();
$n2_children = $n2->getChildren();
$t->is(count($n2_children), 3, 'N2 node has "3 children"');
foreach ($n2_children as $child)
{
  $t->is($child->getLevel(), 2, 'N2 child "level" is "2"');
}

$t->diag('Retrieving children of N3');
$n3 = $n3->reload();
$n3_children = $n3->getChildren();
$t->is(count($n3_children), 0, 'N3 node has "0 children"');

// getNumberOfChildren
$t = new lime_test(3, new lime_output_color());
$t->diag('getNumberOfChildren');
$t->is($root->getNumberOfChildren(), 5, 'returns the right count of children');
$t->is($n2->getNumberOfChildren(), 3, 'returns the right count of children');
$t->is($n3->getNumberOfChildren(), 0, 'returns the right count of children');

// getDescendants
$t = new lime_test(14, new lime_output_color());
$root = $root->reload();
$n2 = $n2->reload();
$n4 = $n4->reload();
$root_descendants = $root->getDescendants();
$n2_descendants = $n2->getDescendants();
$n4_descendants = $n4->getDescendants();
$t->diag('getDescendants');
$t->is(count($root_descendants), 8, 'ROOT node has "8 descendants"');
$valid_levels = array(1, 2, 2, 2, 1, 1, 1, 1);
$i = 0;
foreach ($valid_levels as $valid_level)
{
  $t->is($root_descendants[$i]->getLevel(), $valid_levels[$i], 'ROOT descendant level is valid');
  $i++;
}

$t->is(count($n2_descendants), 3, 'N2 node has "3 descendants"');
$valid_levels = array(2, 2, 2);
$i = 0;
foreach ($valid_levels as $valid_level)
{
  $t->is($n2_descendants[$i]->getLevel(), $valid_levels[$i], 'N2 descendant level is valid');
  $i++;
}

$t->is(count($n4_descendants), 0, 'N4 node "does not have descendants"');

// getNumberOfDescendants
$t = new lime_test(2, new lime_output_color());
$t->diag('getNumberOfDescendants');
$t->is($root->getNumberOfDescendants(), 8, 'returns the right count of descendants for ROOT');
$t->is($n2->getNumberOfDescendants(), 3, 'returns the right count of descendants for N2');

// isRoot
$t = new lime_test(2, new lime_output_color());
$t->diag('isRoot');
$t->ok($root->isRoot(), 'returns true for a root node');
$t->isnt(true, $n1->isRoot(), 'returns false for non-root node');

// hasChildren
$t = new lime_test(3, new lime_output_color());
$t->diag('hasChildren');
$t->is($root->hasChildren(), true, 'ROOT has children');
$t->isnt($n4->hasChildren(), true, 'N4 does not have children');
$t->is($n2->hasChildren(), true, 'N2 has children');

// hasParent
$t = new lime_test(3, new lime_output_color());
$t->diag('hasParent');
$t->isnt($root->hasParent(), true, 'ROOT does not have a parent node');
$t->is($n6->hasParent(), true, 'N6 has a parent node');
$t->is($n7->hasParent(), true, 'N7 has a parent node');

// hasNextSibling
$t = new lime_test(4, new lime_output_color());
$t->diag('hasNextSibling');
$t->isnt($root->hasNextSibling(), true, 'ROOT does not have siblings');
$t->is($n2->hasNextSibling(), true, 'N2 has next sibling');
$t->isnt($n4->hasNextSibling(), true, 'N4 does not have next sibling');
$t->isnt($n5->hasNextSibling(), true, 'N5 does not have next sibling');

// hasPrevSibling
$t = new lime_test(4, new lime_output_color());
$t->diag('hasPrevSibling');
$t->isnt($root->hasPrevSibling(), true, 'ROOT does not have siblings');
$t->isnt($n2->hasPrevSibling(), true, 'N2 does not have previous sibling');
$t->is($n6->hasPrevSibling(), true, 'N6 has previous sibling');
$t->isnt($n3->hasPrevSibling(), true, 'N3 does not have previous sibling');

// isLeaf
$t = new lime_test(3, new lime_output_color());
$t->diag('isLeaf');
$t->isnt($root->isLeaf(), true, 'ROOT is not a leaf');
$t->isnt($n2->isLeaf(), true, 'N2 is not a leaf');
$t->is($n4->isLeaf(), true, 'N4 is a leaf');

// moveToFirstChildOf
$t = new lime_test(58, new lime_output_color());
$t->diag('moveToFirstChildOf');
$t->diag('Move N8 to first child of N1');
$t->diag('root');
$t->diag(' |-N2');
$t->diag('   |-N3');
$t->diag('   |-N7');
$t->diag('   |-N4');
$t->diag(' |-N6');
$t->diag(' |-N1');
$t->diag('   |-N8');
$t->diag(' |-N5');

$n8->moveToFirstChildOf($n1);
$n8->save();

// -- reload nodes
$n1 = $n1->reload();
$n2 = $n2->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$n6 = $n6->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 18, 'root "right" is "18"');
$t->is($root->getLevel(), 0, 'root "level" is "0"');
$t->is($n1->getLeftValue(), 12, 'N1 "left" is "12"');
$t->is($n1->getRightValue(), 15, 'N1 "right" is "15"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 2, 'N2 "left" is "2"');
$t->is($n2->getRightValue(), 9, 'N2 "right" is "9"');
$t->is($n2->getLevel(), 1, 'N2 "level" is "1"');
$t->is($n3->getLeftValue(), 3, 'N3 "left" is "3"');
$t->is($n3->getRightValue(), 4, 'N3 "right" is "4"');
$t->is($n3->getLevel(), 2, 'N3 "level" is "2"');
$t->is($n4->getLeftValue(), 7, 'N4 "left" is "7"');
$t->is($n4->getRightValue(), 8, 'N4 "right" is "8"');
$t->is($n4->getLevel(), 2, 'N4 "level" is "2"');
$t->is($n5->getLeftValue(), 16, 'N5 "left" is "16"');
$t->is($n5->getRightValue(), 17, 'N5 "right" is "17"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n6->getLeftValue(), 10, 'N6 "left" is "10"');
$t->is($n6->getRightValue(), 11, 'N6 "right" is "11"');
$t->is($n6->getLevel(), 1, 'N6 "level" is "1"');
$t->is($n7->getLeftValue(), 5, 'N7 "left" is "5"');
$t->is($n7->getRightValue(), 6, 'N7 "right" is "6"');
$t->is($n7->getLevel(), 2, 'N7 "level" is "2"');
$t->is($n8->getLeftValue(), 13, 'N8 "left" is "13"');
$t->is($n8->getRightValue(), 14, 'N8 "right" is "14"');
$t->is($n8->getLevel(), 2, 'N8 "level" is "2"');
$t->is($n8->getParentIdValue(), $n1->getPrimaryKey(), 'N8 parent id equals N1 id');
$t->is($n8->getScopeIdValue(), $n1->getScopeIdValue(), 'N8 scope id equals N1 scope id');

$t->diag('Move N2 to first child of N8');
$t->diag('root');
$t->diag(' |-N6');
$t->diag(' |-N1');
$t->diag('   |-N8');
$t->diag('     |-N2');
$t->diag('       |-N3');
$t->diag('       |-N7');
$t->diag('       |-N4');
$t->diag(' |-N5');

$n2->moveToFirstChildOf($n8);
$n2->save();

// -- reload nodes
$n1 = $n1->reload();
$n2 = $n2->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$n6 = $n6->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 18, 'root "right" is "18"');
$t->is($root->getLevel(), 0, 'root "level" is "0"');
$t->is($n1->getLeftValue(), 4, 'N1 "left" is "4"');
$t->is($n1->getRightValue(), 15, 'N1 "right" is "15"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 6, 'N2 "left" is "6"');
$t->is($n2->getRightValue(), 13, 'N2 "right" is "13"');
$t->is($n2->getLevel(), 3, 'N2 "level" is "3"');
$t->is($n3->getLeftValue(), 7, 'N3 "left" is "7"');
$t->is($n3->getRightValue(), 8, 'N3 "right" is "8"');
$t->is($n3->getLevel(), 4, 'N3 "level" is "4"');
$t->is($n4->getLeftValue(), 11, 'N4 "left" is "11"');
$t->is($n4->getRightValue(), 12, 'N4 "right" is "12"');
$t->is($n4->getLevel(), 4, 'N4 "level" is "4"');
$t->is($n5->getLeftValue(), 16, 'N5 "left" is "16"');
$t->is($n5->getRightValue(), 17, 'N5 "right" is "17"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n6->getLeftValue(), 2, 'N6 "left" is "2"');
$t->is($n6->getRightValue(), 3, 'N6 "right" is "3"');
$t->is($n6->getLevel(), 1, 'N6 "level" is "1"');
$t->is($n7->getLeftValue(), 9, 'N7 "left" is "9"');
$t->is($n7->getRightValue(), 10, 'N7 "right" is "10"');
$t->is($n7->getLevel(), 4, 'N7 "level" is "4"');
$t->is($n8->getLeftValue(), 5, 'N8 "left" is "5"');
$t->is($n8->getRightValue(), 14, 'N8 "right" is "14"');
$t->is($n8->getLevel(), 2, 'N1 "level" is "2"');
$t->is($n2->getParentIdValue(), $n8->getPrimaryKey(), 'N2 parent id equals N8 id');
$t->is($n2->getScopeIdValue(), $n8->getScopeIdValue(), 'N2 scope id equals N8 scope id');

// moveToLastChildOf
$t = new lime_test(29, new lime_output_color());
$t->diag('moveToLastChildOf');
$t->diag('Move N6 to last child of N8');
$t->diag('root');
$t->diag(' |-N1');
$t->diag('   |-N8');
$t->diag('     |-N2');
$t->diag('       |-N3');
$t->diag('       |-N7');
$t->diag('       |-N4');
$t->diag('     |-N6');
$t->diag(' |-N5');

$n6->moveToLastChildOf($n8);
$n6->save();

// -- reload nodes
$n1 = $n1->reload();
$n2 = $n2->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$n6 = $n6->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 18, 'root "right" is "18"');
$t->is($root->getLevel(), 0, 'root "level" is "0"');
$t->is($n1->getLeftValue(), 2, 'N1 "left" is "2"');
$t->is($n1->getRightValue(), 15, 'N1 "right" is "15"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n2->getLeftValue(), 4, 'N2 "left" is "4"');
$t->is($n2->getRightValue(), 11, 'N2 "right" is "11"');
$t->is($n2->getLevel(), 3, 'N2 "level" is "3"');
$t->is($n3->getLeftValue(), 5, 'N3 "left" is "5"');
$t->is($n3->getRightValue(), 6, 'N3 "right" is "6"');
$t->is($n3->getLevel(), 4, 'N3 "level" is "4"');
$t->is($n4->getLeftValue(), 9, 'N4 "left" is "9"');
$t->is($n4->getRightValue(), 10, 'N4 "right" is "10"');
$t->is($n4->getLevel(), 4, 'N4 "level" is "4"');
$t->is($n5->getLeftValue(), 16, 'N5 "left" is "16"');
$t->is($n5->getRightValue(), 17, 'N5 "right" is "17"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n6->getLeftValue(), 12, 'N6 "left" is "12"');
$t->is($n6->getRightValue(), 13, 'N6 "right" is "13"');
$t->is($n6->getLevel(), 3, 'N6 "level" is "3"');
$t->is($n7->getLeftValue(), 7, 'N7 "left" is "7"');
$t->is($n4->getLevel(), 4, 'N4 "level" is "4"');
$t->is($n7->getRightValue(), 8, 'N7 "right" is "8"');
$t->is($n8->getLeftValue(), 3, 'N8 "left" is "3"');
$t->is($n8->getRightValue(), 14, 'N8 "right" is "14"');
$t->is($n8->getLevel(), 2, 'N8 "level" is "2"');
$t->is($n6->getParentIdValue(), $n8->getPrimaryKey(), 'N6 parent id equals N8 id');
$t->is($n6->getScopeIdValue(), $n8->getScopeIdValue(), 'N6 scope id equals N8 scope id');

// retrieveSiblings
$t = new lime_test(2, new lime_output_color());
$t->diag('retrieveSiblings');
$t->diag('Retrieve siblings of N7');
$expected = array($n3->getId(), $n4->getId());
$got = array();
$levels_got = array();
$levels_expected = array(4, 4);
foreach ($n7->retrieveSiblings() as $node)
{
  $got[] = $node->getId();
  $levels_got[] = $node->getLevel();
}

$t->is($got, $expected, 'retrieveSiblings() returns the right siblings');
$t->is($levels_got, $levels_expected, 'retrieveSiblings() correctly sets node levels');

// delete
$t = new lime_test(27, new lime_output_color());
$t->diag('delete');
$t->diag('Delete node N2');
$t->diag('root');
$t->diag(' |-N1');
$t->diag('   |-N8');
$t->diag('     |-N3');
$t->diag('     |-N7');
$t->diag('     |-N4');
$t->diag('     |-N6');
$t->diag(' |-N5');

$n2->delete();

// -- reload nodes
$n1 = $n1->reload();
$n2 = $n2->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$n6 = $n6->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($root->getRightValue(), 16, 'root "right" is "16"');
$t->is($n1->getLeftValue(), 2, 'N1 "left" is "2"');
$t->is($n1->getRightValue(), 13, 'N1 "right" is "13"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n3->getLeftValue(), 4, 'N3 "left" is "4"');
$t->is($n3->getRightValue(), 5, 'N3 "right" is "5"');
$t->is($n3->getParentIdValue(), $n8->getPrimaryKey(), 'N3 parent id equals N8 id');
$t->is($n3->getLevel(), 3, 'N3 "level" is "3"');
$t->is($n4->getLeftValue(), 8, 'N4 "left" is "8"');
$t->is($n4->getRightValue(), 9, 'N4 "right" is "9"');
$t->is($n4->getParentIdValue(), $n8->getPrimaryKey(), 'N4 parent id equals N8 id');
$t->is($n4->getLevel(), 3, 'N4 "level" is "3"');
$t->is($n5->getLeftValue(), 14, 'N5 "left" is "14"');
$t->is($n5->getRightValue(), 15, 'N5 "right" is "15"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n6->getLeftValue(), 10, 'N6 "left" is "10"');
$t->is($n6->getRightValue(), 11, 'N6 "right" is "11"');
$t->is($n6->getLevel(), 3, 'N6 "level" is "3"');
$t->is($n7->getLeftValue(), 6, 'N7 "left" is "6"');
$t->is($n7->getRightValue(), 7, 'N7 "right" is "7"');
$t->is($n7->getParentIdValue(), $n8->getPrimaryKey(), 'N7 parent id equals N8 id');
$t->is($n7->getLevel(), 3, 'N7 "level" is "3"');
$t->is($n8->getLeftValue(), 3, 'N8 "left" is "3"');
$t->is($n8->getRightValue(), 12, 'N8 "right" is "12"');
$t->is($n8->getLevel(), 2, 'N8 "level" is "2"');

// retrieveFirstChild()
$t = new lime_test(2, new lime_output_color());
$t->diag('retrieveFirstChild');
$fc = $root->retrieveFirstChild();
$t->is($fc->getId(), $n1->getId(), '"ROOT" first child is "N1"');

$fc = $n8->retrieveFirstChild();
$t->is($fc->getId(), $n3->getId(), '"N8" first child is "N3"');

// retrieveLastChild()
$t = new lime_test(2, new lime_output_color());
$t->diag('retrieveLastChild');
$fc = $root->retrieveLastChild();
$t->is($fc->getId(), $n5->getId(), '"ROOT" last child is "N5"');

$fc = $n8->retrieveLastChild();
$t->is($fc->getId(), $n6->getId(), '"N8" last child is "N6"');

// retrieveParent()
$t = new lime_test(3, new lime_output_color());
$t->diag('retrieveParent');
$np = $root->retrieveParent();
$t->is($np, false, 'retrieveParent() returns false for ROOT nodes');

$np = $n8->retrieveParent();
$t->is($np->getId(), $n1->getId(), '"N8" parent is "N1"');

$np = $n4->retrieveParent();
$t->is($np->getId(), $n8->getId(), '"N4" parent is "N8"');

// getPath()
$t = new lime_test(2, new lime_output_color());
$t->diag('getPath');
$target_path_ids = array($root->getId(), $n1->getId(), $n8->getId());
$n7_path = $n7->getPath();
$n7_path_ids = array();
foreach ($n7_path as $node)
{
  $n7_path_ids[] = $node->getId();
}

$t->is(count($n7_path), count($target_path_ids), 'getPath() returns the right number of nodes');
$t->is($n7_path_ids, $target_path_ids, 'getPath() returns the right nodes');

// moveToNextSiblingOf
$t = new lime_test(26, new lime_output_color());
$t->diag('moveToNextSiblingOf');
$t->diag('Move N7 to next sibling of N8');
$t->diag('root');
$t->diag(' |-N1');
$t->diag('   |-N8');
$t->diag('     |-N3');
$t->diag('     |-N4');
$t->diag('     |-N6');
$t->diag('   |-N7');
$t->diag(' |-N5');

$n7->moveToNextSiblingOf($n8);
$n7->save();

// -- reload nodes
$n1 = $n1->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$n6 = $n6->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 16, 'root "right" is "16"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 2, 'N1 "left" is "2"');
$t->is($n1->getRightValue(), 13, 'N1 "right" is "13"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n3->getLeftValue(), 4, 'N3 "left" is "4"');
$t->is($n3->getRightValue(), 5, 'N3 "right" is "5"');
$t->is($n3->getLevel(), 3, 'N3 "level" is "3"');
$t->is($n4->getLeftValue(), 6, 'N4 "left" is "6"');
$t->is($n4->getRightValue(), 7, 'N4 "right" is "7"');
$t->is($n4->getLevel(), 3, 'N4 "level" is "3"');
$t->is($n5->getLeftValue(), 14, 'N5 "left" is "14"');
$t->is($n5->getRightValue(), 15, 'N5 "right" is "15"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n6->getLeftValue(), 8, 'N6 "left" is "8"');
$t->is($n6->getRightValue(), 9, 'N6 "right" is "9"');
$t->is($n6->getLevel(), 3, 'N6 "level" is "3"');
$t->is($n7->getLeftValue(), 11, 'N7 "left" is "11"');
$t->is($n7->getRightValue(), 12, 'N7 "right" is "12"');
$t->is($n8->getLeftValue(), 3, 'N8 "left" is "3"');
$t->is($n8->getRightValue(), 10, 'N8 "right" is "10"');
$t->is($n8->getLevel(), 2, 'N8 "level" is "2"');
$t->is($n7->getParentIdValue(), $n8->getParentIdValue(), 'N7 parent id equals N8 id');
$t->is($n7->getScopeIdValue(), $n8->getScopeIdValue(), 'N7 scope id equals N8 scope id');
$t->is($n7->getLevel(), 2, 'N7 "level" is "2"');

// moveToPrevSiblingOf
$t = new lime_test(26, new lime_output_color());
$t->diag('moveToNextSiblingOf');
$t->diag('Move N4 to next sibling of N8');
$t->diag('root');
$t->diag(' |-N1');
$t->diag('   |-N4');
$t->diag('   |-N8');
$t->diag('     |-N3');
$t->diag('     |-N6');
$t->diag('   |-N7');
$t->diag(' |-N5');

$n4->moveToPrevSiblingOf($n8);
$n4->save();

// -- reload nodes
$n1 = $n1->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$n6 = $n6->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 16, 'root "right" is "16"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n1->getLeftValue(), 2, 'N1 "left" is "2"');
$t->is($n1->getRightValue(), 13, 'N1 "right" is "13"');
$t->is($n1->getLevel(), 1, 'N1 "level" is "1"');
$t->is($n3->getLeftValue(), 6, 'N3 "left" is "6"');
$t->is($n3->getRightValue(), 7, 'N3 "right" is "7"');
$t->is($n3->getLevel(), 3, 'N3 "level" is "3"');
$t->is($n4->getLeftValue(), 3, 'N4 "left" is "3"');
$t->is($n4->getRightValue(), 4, 'N4 "right" is "4"');
$t->is($n4->getLevel(), 2, 'N4 "level" is "2"');
$t->is($n5->getLeftValue(), 14, 'N5 "left" is "14"');
$t->is($n5->getRightValue(), 15, 'N5 "right" is "15"');
$t->is($n5->getLevel(), 1, 'N5 "level" is "1"');
$t->is($n6->getLeftValue(), 8, 'N6 "left" is "8"');
$t->is($n6->getRightValue(), 9, 'N6 "right" is "9"');
$t->is($n6->getLevel(), 3, 'N6 "level" is "3"');
$t->is($n7->getLeftValue(), 11, 'N7 "left" is "11"');
$t->is($n7->getRightValue(), 12, 'N7 "right" is "12"');
$t->is($n7->getLevel(), 2, 'N7 "level" is "2"');
$t->is($n8->getLeftValue(), 5, 'N8 "left" is "5"');
$t->is($n8->getRightValue(), 10, 'N8 "right" is "10"');
$t->is($n8->getLevel(), 2, 'N8 "level" is "2"');
$t->is($n4->getParentIdValue(), $n8->getParentIdValue(), 'N4 parent id equals N8 id');
$t->is($n4->getScopeIdValue(), $n8->getScopeIdValue(), 'N4 scope id equals N8 scope id');

// getParent
$t = new lime_test(4, new lime_output_color());
$t->diag('getParent');

// -- reload nodes
$n1 = $n1->reload();
$n3 = $n3->reload();
$n4 = $n4->reload();
$n5 = $n5->reload();
$n6 = $n6->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($n3->getParent()->equals($n8), true, 'N8 is parent of N3');
$t->is($n8->getParent()->equals($n1), true, 'N1 is parent of N8');
$t->is($n1->getParent()->equals($root), true, 'ROOT is parent of N1');
$t->is($root->getParent(), null, 'ROOT parent is null');

// deleteChildren
$t = new lime_test(28, new lime_output_color());
$t->diag('deleteChildren');
$t->diag('Delete ROOT children');
$t->diag('root');
$t->diag(' |-N4');
$t->diag(' |-N8');
$t->diag('   |-N3');
$t->diag('   |-N6');
$t->diag(' |-N7');

$root->deleteChildren();

// -- reload nodes
$n3 = $n3->reload();
$n4 = $n4->reload();
$n6 = $n6->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 12, 'root "right" is "12"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n3->getLeftValue(), 5, 'N3 "left" is "5"');
$t->is($n3->getRightValue(), 6, 'N3 "right" is "6"');
$t->is($n3->getParentIdValue(), $n8->getPrimaryKey(), 'N3 parent is N8');
$t->is($n3->getScopeIdValue(), $n8->getScopeIdValue(), 'N3 scope id equals N8 scope id');
$t->is($n3->getLevel(), 2, 'N3 "level" is "2"');
$t->is($n4->getLeftValue(), 2, 'N4 "left" is "2"');
$t->is($n4->getRightValue(), 3, 'N4 "right" is "3"');
$t->is($n4->getParentIdValue(), $root->getPrimaryKey(), 'N4 parent is ROOT');
$t->is($n4->getScopeIdValue(), $root->getScopeIdValue(), 'N4 scope id equals ROOT scope id');
$t->is($n4->getLevel(), 1, 'N4 "level" is "1"');
$t->is($n6->getLeftValue(), 7, 'N6 "left" is "7"');
$t->is($n6->getRightValue(), 8, 'N6 "right" is "8"');
$t->is($n6->getParentIdValue(), $n8->getPrimaryKey(), 'N6 parent is N8');
$t->is($n6->getScopeIdValue(), $n8->getScopeIdValue(), 'N6 scope id equals N8 scope id');
$t->is($n6->getLevel(), 2, 'N6 "level" is "2"');
$t->is($n7->getLeftValue(), 10, 'N7 "left" is "10"');
$t->is($n7->getRightValue(), 11, 'N7 "right" is "11"');
$t->is($n7->getParentIdValue(), $root->getPrimaryKey(), 'N7 parent is ROOT');
$t->is($n7->getScopeIdValue(), $root->getScopeIdValue(), 'N7 scope id equals ROOT scope id');
$t->is($n7->getLevel(), 1, 'N7 "level" is "1"');
$t->is($n8->getLeftValue(), 4, 'N8 "left" is "4"');
$t->is($n8->getRightValue(), 9, 'N8 "right" is "9"');
$t->is($n8->getParentIdValue(), $root->getPrimaryKey(), 'N8 parent is ROOT');
$t->is($n8->getScopeIdValue(), $root->getScopeIdValue(), 'N8 scope id equals ROOT scope id');
$t->is($n8->getLevel(), 1, 'N8 "level" is "1"');

// deleteDescendants
$t = new lime_test(18, new lime_output_color());
$t->diag('deleteDescendants');
$t->diag('Delete N8 descendants');
$t->diag('root');
$t->diag(' |-N4');
$t->diag(' |-N8');
$t->diag(' |-N7');

// Insert this node for more meaningful unit test
$n9 = _create_node();
$n9->insertAsLastChildOf($n6);
$n9->save();

// -- reload nodes
$n4 = $n4->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$n8->deleteDescendants();

// -- reload nodes
$n4 = $n4->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 8, 'root "right" is "8"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n4->getLeftValue(), 2, 'N4 "left" is "2"');
$t->is($n4->getRightValue(), 3, 'N4 "right" is "3"');
$t->is($n4->getParentIdValue(), $root->getPrimaryKey(), 'N4 parent is ROOT');
$t->is($n4->getScopeIdValue(), $root->getScopeIdValue(), 'N4 scope id equals ROOT scope id');
$t->is($n4->getLevel(), 1, 'N4 "level" is "1"');
$t->is($n7->getLeftValue(), 6, 'N7 "left" is "6"');
$t->is($n7->getRightValue(), 7, 'N7 "right" is "7"');
$t->is($n7->getParentIdValue(), $root->getPrimaryKey(), 'N7 parent is ROOT');
$t->is($n7->getScopeIdValue(), $root->getScopeIdValue(), 'N7 scope id equals ROOT scope id');
$t->is($n7->getLevel(), 1, 'N7 "level" is "1"');
$t->is($n8->getLeftValue(), 4, 'N8 "left" is "4"');
$t->is($n8->getRightValue(), 5, 'N8 "right" is "5"');
$t->is($n8->getParentIdValue(), $root->getPrimaryKey(), 'N8 parent is ROOT');
$t->is($n8->getScopeIdValue(), $root->getScopeIdValue(), 'N8 scope id equals ROOT scope id');
$t->is($n8->getLevel(), 1, 'N8 "level" is "1"');

// insertAsParentOf
$t = new lime_test(19, new lime_output_color());
$t->diag('insertAsParentOf');
$t->diag('Insert N8 as parent of N4');
$t->diag('root');
$t->diag(' |-N8');
$t->diag('   |-N4');
$t->diag(' |-N7');

$n8->insertAsParentOf($n4);
$n8->save();

// -- reload nodes
$n4 = $n4->reload();
$n7 = $n7->reload();
$n8 = $n8->reload();
$root = $root->reload();

$t->is($root->getLeftValue(), 1, 'root "left" is "1"');
$t->is($root->getRightValue(), 8, 'root "right" is "8"');
$t->is($root->getLevel(), 0, 'ROOT "level" is "0"');
$t->is($n4->getLeftValue(), 3, 'N4 "left" is "3"');
$t->is($n4->getRightValue(), 4, 'N4 "right" is "4"');
$t->is($n4->getParentIdValue(), $n8->getPrimaryKey(), 'N4 parent is N8');
$t->is($n4->getScopeIdValue(), $n8->getScopeIdValue(), 'N4 scope id equals N8 scope id');
$t->is($n4->getLevel(), 2, 'N4 "level" is "2"');
$t->is($n7->getLeftValue(), 6, 'N7 "left" is "6"');
$t->is($n7->getRightValue(), 7, 'N7 "right" is "7"');
$t->is($n7->getParentIdValue(), $root->getPrimaryKey(), 'N7 parent is ROOT');
$t->is($n7->getScopeIdValue(), $root->getScopeIdValue(), 'N7 scope id equals ROOT scope id');
$t->is($n7->getLevel(), 1, 'N7 "level" is "1"');
$t->is($n8->getLeftValue(), 2, 'N8 "left" is "2"');
$t->is($n8->getRightValue(), 5, 'N8 "right" is "5"');
$t->is($n8->getParentIdValue(), $root->getPrimaryKey(), 'N8 parent is ROOT');
$t->is($n8->getScopeIdValue(), $root->getScopeIdValue(), 'N8 scope id equals ROOT scope id');
$t->is($n8->getLevel(), 1, 'N8 "level" is "1"');

try
{
  $n8->insertAsParentOf($root);
  $t->fail('insertAsParentOf() throws an exception when asked to insert a node as parent of a root node');
}
catch (Exception $e)
{
  $t->pass('insertAsParentOf() throws an exception when asked to insert a node as parent of a root node');
}

// isChildOf
$t = new lime_test(2, new lime_output_color());
$t->diag('isChildOf');
$t->is($n4->isChildOf($n8), true, 'isChildOf() returns true when given node is node parent');
$t->is($n4->isChildOf($root), false, 'isChildOf() returns false when given node is not node parent');

// isDescendantOf
$t = new lime_test(3, new lime_output_color());
$t->diag('isDescendantOf');
$t->is($n4->isDescendantOf($n8), true, 'isDescendantOf() returns true when given node is node direct parent');
$t->is($n4->isDescendantOf($root), true, 'isDescendantOf() returns true when given node grand-parent');
$t->is($root->isDescendantOf($n4), false, 'isDescendantOf() returns false when node is ROOT node');

// Helper functions

/**
 * Node creation "abstraction".
 * 
 * @return  BaseObject
 */
function _create_node()
{
  $classname = NESTEDSETS_CLASS;
  
  if (!class_exists($classname))
  {
    throw new Exception(sprintf('Unknow class "%s"', $classname));
  }
  
  $node = new $classname();

  return new $node;
}
