PageRenderTime 153ms CodeModel.GetById 78ms app.highlight 66ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/tests/lltreeiterators_test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1213 lines | 803 code | 69 blank | 341 comment | 34 complexity | 06724fee3e7f901bfd87e38367661e4a MD5 | raw file
   1/**
   2 * @file   lltreeiterators.cpp
   3 * @author Nat Goodspeed
   4 * @date   2008-08-20
   5 * @brief  Test of lltreeiterators.h
   6 * 
   7 * $LicenseInfo:firstyear=2008&license=viewerlgpl$
   8 * Second Life Viewer Source Code
   9 * Copyright (C) 2010, Linden Research, Inc.
  10 * 
  11 * This library is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU Lesser General Public
  13 * License as published by the Free Software Foundation;
  14 * version 2.1 of the License only.
  15 * 
  16 * This library is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19 * Lesser General Public License for more details.
  20 * 
  21 * You should have received a copy of the GNU Lesser General Public
  22 * License along with this library; if not, write to the Free Software
  23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  24 * 
  25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  26 * $/LicenseInfo$
  27 */
  28
  29// Precompiled header
  30#include "linden_common.h"
  31
  32
  33// STL headers
  34// std headers
  35#include <iostream>
  36#include <sstream>
  37#include <string>
  38// external library headers
  39#include <boost/bind.hpp>
  40#include <boost/range/iterator_range.hpp>
  41#include <boost/foreach.hpp>
  42
  43// associated header
  44#include "../lltreeiterators.h"
  45#include "../llpointer.h"
  46
  47#include "../test/lltut.h"
  48
  49/*****************************************************************************
  50*   tut test group
  51*****************************************************************************/
  52namespace tut
  53{
  54    struct iter_data
  55    {
  56    };
  57    typedef test_group<iter_data> iter_group;
  58    typedef iter_group::object iter_object;
  59    tut::iter_group ig("LLTreeIterators");
  60} // namespace tut
  61
  62/*****************************************************************************
  63*   boost::get_pointer() specialization for LLPointer<>
  64*****************************************************************************/
  65// This specialization of boost::get_pointer() undoubtedly belongs in
  66// llmemory.h. It's used by boost::bind() so that you can pass an
  67// LLPointer<Foo> as well as a Foo* to a functor such as
  68// boost::bind(&Foo::method, _1).
  69//namespace boost
  70//{
  71    template <class NODE>
  72    NODE* get_pointer(const LLPointer<NODE>& ptr) { return ptr.get(); }
  73//};
  74
  75/*****************************************************************************
  76*   ScopeLabel
  77*****************************************************************************/
  78class ScopeLabel
  79{
  80public:
  81    ScopeLabel(const std::string& label): mLabel(label)
  82    {
  83        std::cout << "Entering " << mLabel << '\n';
  84    }
  85    ~ScopeLabel()
  86    {
  87        std::cout << "Leaving  " << mLabel << '\n';
  88    }
  89private:
  90    std::string mLabel;
  91};
  92
  93/*****************************************************************************
  94*   Cleanup
  95*****************************************************************************/
  96// Yes, we realize this is redundant with auto_ptr and LLPointer and all
  97// kinds of better mechanisms. But in this particular source file, we need to
  98// test nodes managed with plain old dumb pointers as well as nodes managed
  99// with LLPointer, so we introduce this mechanism.
 100//
 101// In the general case, when we declare a Cleanup for some pointer, delete the
 102// pointer when the Cleanup goes out of scope.
 103template <typename PTRTYPE>
 104struct Cleanup
 105{
 106    Cleanup(const PTRTYPE& ptr): mPtr(ptr) {}
 107    ~Cleanup()
 108    {
 109        delete mPtr;
 110    }
 111    PTRTYPE mPtr;
 112};
 113
 114// But when the pointer is an LLPointer<something>, Cleanup is a no-op:
 115// LLPointer will handle the cleanup automagically.
 116template <typename NODE>
 117struct Cleanup< LLPointer<NODE> >
 118{
 119    Cleanup(const LLPointer<NODE>& ptr) {}
 120    ~Cleanup() {}
 121};
 122
 123/*****************************************************************************
 124*   Expected
 125*****************************************************************************/
 126// Expected is a base class used to capture the expected results -- a sequence
 127// of string node names -- from one of our traversals of this example data.
 128// Its subclasses initialize it with a pair of string iterators. It's not
 129// strictly necessary to customize Expected to model Boost.Range, it's just
 130// convenient.
 131struct Expected
 132{
 133    template <typename ITER>
 134    Expected(ITER begin, ITER end):
 135        strings(begin, end)
 136    {}
 137    /*------ The following are to make Expected work with Boost.Range ------*/
 138    typedef std::vector<std::string> container_type;
 139    typedef container_type::iterator iterator;
 140    typedef container_type::const_iterator const_iterator;
 141    typedef container_type::size_type size_type;
 142    container_type strings;
 143    iterator begin() { return strings.begin(); }
 144    iterator end()   { return strings.end(); }
 145    size_type size() { return strings.size(); }
 146    const_iterator begin() const { return strings.begin(); }
 147    const_iterator end() const   { return strings.end(); }
 148};
 149
 150// We have a couple of generic Expected template subclasses. This list of
 151// strings is used for the "else" case when all specializations fail.
 152const char* bad_strings[] = { "FAIL" };
 153
 154/*****************************************************************************
 155*   verify()
 156*****************************************************************************/
 157// test function: given (an object modeling) a Boost.Range of tree nodes,
 158// compare the sequence of visited node names with a range of expected name
 159// strings. Report success both with std::cout output and a bool return. The
 160// string desc parameter is to identify the different tests.
 161template <typename NODERANGE, typename STRINGRANGE>
 162bool verify(const std::string& desc, NODERANGE noderange, STRINGRANGE expected)
 163{
 164    typename boost::range_iterator<NODERANGE>::type
 165        nri = boost::begin(noderange),
 166        nrend = boost::end(noderange);
 167    typename boost::range_iterator<STRINGRANGE>::type
 168        sri = boost::begin(expected),
 169        srend = boost::end(expected);
 170    // We choose to loop over both sequences explicitly rather than using
 171    // std::equal() or std::lexicographical_compare(). The latter tells you
 172    // whether one sequence is *less* than the other -- it doesn't tell you
 173    // equality. std::equal() needs you to verify the sequence lengths ahead
 174    // of time. Anyway, comparing explicitly allows us to report much more
 175    // information about any sequence mismatch.
 176    for ( ; nri != nrend && sri != srend; ++nri, ++sri)
 177    {
 178        if ((*nri)->name() != *sri)
 179        {
 180            std::cout << desc << " mismatch: "
 181                      << "expected " << *sri << ", got " << (*nri)->name() << "\n";
 182            return false;
 183        }
 184    }
 185    if (nri != nrend)
 186    {
 187        std::cout << desc << " produced too many items:\n";
 188        for ( ; nri != nrend; ++nri)
 189        {
 190            std::cout << "  " << (*nri)->name() << '\n';
 191        }
 192        return false;
 193    }
 194    if (sri != srend)
 195    {
 196        std::cout << desc << " produced too few items, omitting:\n";
 197        for ( ; sri != srend; ++sri)
 198        {
 199            std::cout << "  " << *sri << '\n';
 200        }
 201        return false;
 202    }
 203//  std::cout << desc << " test passed\n";
 204    return true;
 205}
 206
 207/*****************************************************************************
 208*   PlainNode: LLLinkIter, non-refcounted
 209*****************************************************************************/
 210class PlainNode
 211{
 212public:
 213    PlainNode(const std::string& name, PlainNode* next=NULL):
 214        mName(name),
 215        mNext(next)
 216    {}
 217    ~PlainNode()
 218    {
 219        delete mNext;
 220    }
 221    std::string name() const { return mName; }
 222    PlainNode* next() const { return mNext; }
 223public:                             // if this were 'private', couldn't bind mNext
 224    PlainNode* mNext;
 225private:
 226    std::string mName;
 227};
 228
 229namespace tut
 230{
 231    template<> template<>
 232    void iter_object::test<1>()
 233    {
 234//      set_test_name("LLLinkedIter -- non-refcounted class");
 235        PlainNode* last(new PlainNode("c"));
 236        PlainNode* second(new PlainNode("b", last));
 237        PlainNode* first(new PlainNode("a", second));
 238        Cleanup<PlainNode*> cleanup(first);
 239        static const char* cseq[] = { "a", "b", "c" };
 240        Expected seq(boost::begin(cseq), boost::end(cseq));
 241        std::string desc1("Iterate by public link member");
 242//      std::cout << desc1 << ":\n";
 243        // Try instantiating an iterator with NULL. This test is less about
 244        // "did we iterate once?" than "did we avoid blowing up?"
 245        for (LLLinkedIter<PlainNode> pni(NULL, boost::bind(&PlainNode::mNext, _1)), end;
 246             pni != end; ++pni)
 247        {
 248//          std::cout << (*pni)->name() << '\n';
 249            ensure("LLLinkedIter<PlainNode>(NULL)", false);
 250        }
 251        ensure(desc1,
 252               verify(desc1,
 253                      boost::make_iterator_range(LLLinkedIter<PlainNode>(first,
 254                                                                         boost::bind(&PlainNode::mNext, _1)),
 255                                                 LLLinkedIter<PlainNode>()),
 256                      seq));
 257        std::string desc2("Iterate by next() method");
 258//      std::cout << desc2 << ":\n";
 259//      for (LLLinkedIter<PlainNode> pni(first, boost::bind(&PlainNode::next, _1)); ! (pni == end); ++pni)
 260//          std::cout << (**pni).name() << '\n';
 261        ensure(desc2,
 262               verify(desc2,
 263                      boost::make_iterator_range(LLLinkedIter<PlainNode>(first,
 264                                                                         boost::bind(&PlainNode::next, _1)),
 265                                                 LLLinkedIter<PlainNode>()),
 266                      seq));
 267        {
 268//          LLLinkedIter<PlainNode> pni(first, boost::bind(&PlainNode::next, _1));
 269//          std::cout << "First  is " << (*pni++)->name() << '\n';
 270//          std::cout << "Second is " << (*pni  )->name() << '\n';
 271        }
 272        {
 273            LLLinkedIter<PlainNode> pni(first, boost::bind(&PlainNode::next, _1));
 274            ensure_equals("first",  (*pni++)->name(), "a");
 275            ensure_equals("second", (*pni  )->name(), "b");
 276        }
 277    }
 278} // tut
 279
 280/*****************************************************************************
 281*   RCNode: LLLinkIter, refcounted
 282*****************************************************************************/
 283class RCNode;
 284typedef LLPointer<RCNode> RCNodePtr;
 285
 286class RCNode: public LLRefCount
 287{
 288public:
 289    RCNode(const std::string& name, const RCNodePtr& next=RCNodePtr()):
 290        mName(name),
 291        mNext(next)
 292    {
 293//      std::cout << "New  RCNode(" << mName << ")\n";
 294    }
 295    RCNode(const RCNode& that):
 296        mName(that.mName),
 297        mNext(that.mNext)
 298    {
 299//      std::cout << "Copy RCNode(" << mName << ")\n";
 300    }
 301    virtual ~RCNode();
 302    std::string name() const { return mName; }
 303    RCNodePtr next() const { return mNext; }
 304public:                             // if this were 'private', couldn't bind mNext
 305    RCNodePtr mNext;
 306private:
 307    std::string mName;
 308};
 309
 310std::ostream& operator<<(std::ostream& out, const RCNode& node)
 311{
 312    out << "RCNode(" << node.name() << ')';
 313    return out;
 314}
 315
 316// This string contains the node name of the last RCNode destroyed. We use it
 317// to validate that LLLinkedIter<RCNode> in fact contains LLPointer<RCNode>,
 318// and that therefore an outstanding LLLinkedIter to an instance of a
 319// refcounted class suffices to keep that instance alive.
 320std::string last_RCNode_destroyed;
 321
 322RCNode::~RCNode()
 323{
 324//  std::cout << "Kill " << *this << "\n";
 325    last_RCNode_destroyed = mName;
 326}
 327
 328namespace tut
 329{
 330    template<> template<>
 331    void iter_object::test<2>()
 332    {
 333//      set_test_name("LLLinkedIter -- refcounted class");
 334        LLLinkedIter<RCNode> rcni, end2;
 335        {
 336//          ScopeLabel label("inner scope");
 337            RCNodePtr head(new RCNode("x", new RCNode("y", new RCNode("z"))));
 338//          for (rcni = LLLinkedIter<RCNode>(head, boost::bind(&RCNode::mNext, _1)); rcni != end2; ++rcni)
 339//              std::cout << **rcni << '\n';
 340            rcni = LLLinkedIter<RCNode>(head, boost::bind(&RCNode::next, _1));
 341        }
 342//      std::cout << "Now the LLLinkedIter<RCNode> is the only remaining reference to RCNode chain\n";
 343        ensure_equals(last_RCNode_destroyed, "");
 344        ensure(rcni != end2);
 345        ensure_equals((*rcni)->name(), "x");
 346        ++rcni;
 347        ensure_equals(last_RCNode_destroyed, "x");
 348        ensure(rcni != end2);
 349        ensure_equals((*rcni)->name(), "y");
 350        ++rcni;
 351        ensure_equals(last_RCNode_destroyed, "y");
 352        ensure(rcni != end2);
 353        ensure_equals((*rcni)->name(), "z");
 354        ++rcni;
 355        ensure_equals(last_RCNode_destroyed, "z");
 356        ensure(rcni == end2);
 357    }
 358}
 359
 360/*****************************************************************************
 361*   TreeNode
 362*****************************************************************************/
 363class TreeNode;
 364typedef LLPointer<TreeNode> TreeNodePtr;
 365
 366/**
 367 * TreeNode represents a refcounted tree-node class that hasn't (yet) been
 368 * modified to incorporate LLTreeIter methods. This illustrates how you can
 369 * use tree iterators either standalone, or with free functions.
 370 */
 371class TreeNode: public LLRefCount
 372{
 373public:
 374    typedef std::vector<TreeNodePtr> list_type;
 375    typedef list_type::const_iterator child_iterator;
 376
 377    // To avoid cycles, use a "weak" raw pointer for the parent link
 378    TreeNode(const std::string& name, TreeNode* parent=0):
 379        mParent(parent),
 380        mName(name)
 381    {}
 382    TreeNodePtr newChild(const std::string& name)
 383    {
 384        TreeNodePtr child(new TreeNode(name, this));
 385        mChildren.push_back(child);
 386        return child;
 387    }
 388    std::string name() const { return mName; }
 389    TreeNodePtr getParent() const { return mParent; }
 390    child_iterator child_begin() const { return mChildren.begin(); }
 391    child_iterator child_end() const   { return mChildren.end(); }
 392private:
 393    std::string mName;
 394    // To avoid cycles, use a "weak" raw pointer for the parent link
 395    TreeNode* mParent;
 396    list_type mChildren;
 397};
 398
 399/**
 400 * This is an example of a helper function to facilitate iterating from a
 401 * TreeNode up to the root or down from the root (see LLTreeIter::RootIter).
 402 *
 403 * Example:
 404 * @code
 405 * BOOST_FOREACH(TreeNodePtr node, getRootRange<LLTreeIter::UP>(somenode))
 406 * {
 407 *     std::cout << node->name() << '\n';
 408 * }
 409 * @endcode
 410 */
 411template <LLTreeIter::RootIter DISCRIM>
 412boost::iterator_range< LLTreeRootIter<DISCRIM, TreeNode> >
 413getRootRange(const TreeNodePtr& node)
 414{
 415    typedef LLTreeRootIter<DISCRIM, TreeNode> iter_type;
 416    typedef boost::iterator_range<iter_type> range_type;
 417    return range_type(iter_type(node, boost::bind(&TreeNode::getParent, _1)),
 418                      iter_type());
 419}
 420
 421/**
 422 * This is an example of a helper function to facilitate walking a given
 423 * TreeNode's subtree in any supported order (see LLTreeIter::WalkIter).
 424 *
 425 * Example:
 426 * @code
 427 * BOOST_FOREACH(TreeNodePtr node, getWalkRange<LLTreeIter::DFS_PRE>(root))
 428 * {
 429 *     std::cout << node->name() << '\n';
 430 * }
 431 * @endcode
 432 */
 433template <LLTreeIter::WalkIter DISCRIM>
 434boost::iterator_range< LLTreeWalkIter<DISCRIM, TreeNode, TreeNode::child_iterator> >
 435getWalkRange(const TreeNodePtr& node)
 436{
 437    typedef LLTreeWalkIter<DISCRIM, TreeNode, TreeNode::child_iterator> iter_type;
 438    typedef boost::iterator_range<iter_type> range_type;
 439    return range_type(iter_type(node,
 440                                boost::bind(&TreeNode::child_begin, _1),
 441                                boost::bind(&TreeNode::child_end, _1)),
 442                      iter_type());
 443}
 444
 445/*****************************************************************************
 446*   EnhancedTreeNode
 447*****************************************************************************/
 448class EnhancedTreeNode;
 449typedef LLPointer<EnhancedTreeNode> EnhancedTreeNodePtr;
 450
 451/**
 452 * More typically, you enhance the tree-node class itself with template
 453 * methods like the above. This EnhancedTreeNode class illustrates the
 454 * technique. Normally, of course, you'd simply add these methods to TreeNode;
 455 * we put them in a separate class to preserve the undecorated TreeNode class
 456 * to illustrate (and test) the use of plain tree iterators and standalone
 457 * helper functions.
 458 *
 459 * We originally implemented EnhancedTreeNode as a subclass of TreeNode -- but
 460 * because TreeNode stores and manipulates TreeNodePtrs and TreeNode*s,
 461 * reusing its methods required so much ugly downcast logic that we gave up
 462 * and restated the whole class. Bear in mind that logically these aren't two
 463 * separate classes; logically they're two snapshots of the @em same class at
 464 * different moments in time.
 465 */
 466class EnhancedTreeNode: public LLRefCount
 467{
 468public:
 469    /*-------------- The following is restated from TreeNode ---------------*/
 470    typedef std::vector<EnhancedTreeNodePtr> list_type;
 471    typedef list_type::const_iterator child_iterator;
 472
 473    // To avoid cycles, use a "weak" raw pointer for the parent link
 474    EnhancedTreeNode(const std::string& name, EnhancedTreeNode* parent=0):
 475        mParent(parent),
 476        mName(name)
 477    {}
 478    EnhancedTreeNodePtr newChild(const std::string& name)
 479    {
 480        EnhancedTreeNodePtr child(new EnhancedTreeNode(name, this));
 481        mChildren.push_back(child);
 482        return child;
 483    }
 484    std::string name() const { return mName; }
 485    EnhancedTreeNodePtr getParent() const { return mParent; }
 486    child_iterator child_begin() const { return mChildren.begin(); }
 487    child_iterator child_end() const   { return mChildren.end(); }
 488
 489private:
 490    std::string mName;
 491    // To avoid cycles, use a "weak" raw pointer for the parent link
 492    EnhancedTreeNode* mParent;
 493    list_type mChildren;
 494public:
 495    /*----- End of TreeNode; what follows is new with EnhancedTreeNode -----*/
 496
 497    /**
 498     * Because the type of the iterator range returned by getRootRange()
 499     * depends on the discriminator enum value, instead of a simple typedef we
 500     * use a templated struct. Example usage:
 501     *
 502     * @code
 503     * for (EnhancedTreeNode::root_range<LLTreeIter::UP>::type range =
 504     *      somenode->getRootRange<LLTreeIter::UP>();
 505     *      range.first != range.second; ++range.first)
 506     * {
 507     *     std::cout << (*range.first)->name() << '\n';
 508     * }
 509     * @endcode
 510     */
 511    template <LLTreeIter::RootIter DISCRIM>
 512    struct root_range
 513    {
 514        typedef boost::iterator_range< LLTreeRootIter<DISCRIM, EnhancedTreeNode> > type;
 515    };
 516
 517    /**
 518     * Helper method for walking up to (or down from) the tree root. See
 519     * LLTreeIter::RootIter.
 520     *
 521     * Example usage:
 522     * @code
 523     * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getRootRange<LLTreeIter::UP>())
 524     * {
 525     *     std::cout << node->name() << '\n';
 526     * }
 527     * @endcode
 528     */
 529    template <LLTreeIter::RootIter DISCRIM>
 530    typename root_range<DISCRIM>::type getRootRange() const
 531    {
 532        typedef typename root_range<DISCRIM>::type range_type;
 533        typedef typename range_type::iterator iter_type;
 534        return range_type(iter_type(const_cast<EnhancedTreeNode*>(this),
 535                                    boost::bind(&EnhancedTreeNode::getParent, _1)),
 536                          iter_type());
 537    }
 538
 539    /**
 540     * Because the type of the iterator range returned by getWalkRange()
 541     * depends on the discriminator enum value, instead of a simple typedef we
 542     * use a templated stuct. Example usage:
 543     *
 544     * @code
 545     * for (EnhancedTreeNode::walk_range<LLTreeIter::DFS_PRE>::type range =
 546     *      somenode->getWalkRange<LLTreeIter::DFS_PRE>();
 547     *      range.first != range.second; ++range.first)
 548     * {
 549     *     std::cout << (*range.first)->name() << '\n';
 550     * }
 551     * @endcode
 552     */
 553    template <LLTreeIter::WalkIter DISCRIM>
 554    struct walk_range
 555    {
 556        typedef boost::iterator_range< LLTreeWalkIter<DISCRIM,
 557                                                      EnhancedTreeNode,
 558                                                      EnhancedTreeNode::child_iterator> > type;
 559    };
 560
 561    /**
 562     * Helper method for walking a given node's subtree in any supported
 563     * order (see LLTreeIter::WalkIter).
 564     *
 565     * Example usage:
 566     * @code
 567     * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getWalkRange<LLTreeIter::DFS_PRE>())
 568     * {
 569     *     std::cout << node->name() << '\n';
 570     * }
 571     * @endcode
 572     */
 573    template <LLTreeIter::WalkIter DISCRIM>
 574    typename walk_range<DISCRIM>::type getWalkRange() const
 575    {
 576        typedef typename walk_range<DISCRIM>::type range_type;
 577        typedef typename range_type::iterator iter_type;
 578        return range_type(iter_type(const_cast<EnhancedTreeNode*>(this),
 579                                    boost::bind(&EnhancedTreeNode::child_begin, _1),
 580                                    boost::bind(&EnhancedTreeNode::child_end, _1)),
 581                          iter_type());
 582    }
 583};
 584
 585/*****************************************************************************
 586*   PlainTree
 587*****************************************************************************/
 588struct PlainTree
 589{
 590    PlainTree(const std::string& name, PlainTree* parent=0):
 591        mName(name),
 592        mParent(parent),
 593        mNextSibling(0),
 594        mFirstChild(0)
 595    {
 596        mLastChildLink = &mFirstChild;
 597    }
 598    ~PlainTree()
 599    {
 600        delete mNextSibling;
 601        delete mFirstChild;
 602    }
 603    PlainTree* newChild(const std::string& name)
 604    {
 605        PlainTree* child(new PlainTree(name, this));
 606        *mLastChildLink = child;
 607        mLastChildLink = &child->mNextSibling;
 608        return child;
 609    }
 610    std::string name() const { return mName; }
 611
 612    std::string mName;
 613    PlainTree* mParent;
 614    PlainTree* mNextSibling;
 615    PlainTree* mFirstChild;
 616    PlainTree** mLastChildLink;
 617};
 618
 619// This "classic" tree tracks each node's children with a linked list anchored
 620// at the parent's mFirstChild and linked through each child's mNextSibling.
 621// LLTreeDFSIter<> and LLTreeBFSIter<> need functors to return begin()/end()
 622// iterators over a given node's children. But because this tree's children
 623// aren't stored in an STL container, we can't just export that container's
 624// begin()/end(). Instead we'll use LLLinkedIter<> to view the hand-maintained
 625// linked list as an iterator range. The straightforward way to do that would
 626// be to add child_begin() and child_end() methods. But let's say (for the
 627// sake of argument) that this struct is so venerable we don't dare modify it
 628// even to add new methods. Well, we can use free functions (or functors) too.
 629LLLinkedIter<PlainTree> PlainTree_child_begin(PlainTree* node)
 630{
 631    return LLLinkedIter<PlainTree>(node->mFirstChild, boost::bind(&PlainTree::mNextSibling, _1));
 632}
 633
 634LLLinkedIter<PlainTree> PlainTree_child_end(PlainTree* node)
 635{
 636    return LLLinkedIter<PlainTree>();
 637}
 638
 639/**
 640 * This is an example of a helper function to facilitate iterating from a
 641 * PlainTree up to the root or down from the root (see LLTreeIter::RootIter).
 642 * Note that we're simply overloading the same getRootRange() helper function
 643 * name we used for TreeNode.
 644 *
 645 * Example:
 646 * @code
 647 * BOOST_FOREACH(PlainTree* node, getRootRange<LLTreeIter::UP>(somenode))
 648 * {
 649 *     std::cout << node->name() << '\n';
 650 * }
 651 * @endcode
 652 */
 653template <LLTreeIter::RootIter DISCRIM>
 654boost::iterator_range< LLTreeRootIter<DISCRIM, PlainTree> >
 655getRootRange(PlainTree* node)
 656{
 657    typedef LLTreeRootIter<DISCRIM, PlainTree> iter_type;
 658    typedef boost::iterator_range<iter_type> range_type;
 659    return range_type(iter_type(node, boost::bind(&PlainTree::mParent, _1)),
 660                      iter_type());
 661}
 662
 663/**
 664 * This is an example of a helper function to facilitate walking a given
 665 * PlainTree's subtree in any supported order (see LLTreeIter::WalkIter). Note
 666 * that we're simply overloading the same getWalkRange() helper function name
 667 * we used for TreeNode.
 668 *
 669 * Example:
 670 * @code
 671 * BOOST_FOREACH(PlainTree* node, getWalkRange<LLTreeIter::DFS_PRE>(root))
 672 * {
 673 *     std::cout << node->name() << '\n';
 674 * }
 675 * @endcode
 676 */
 677template <LLTreeIter::WalkIter DISCRIM>
 678boost::iterator_range< LLTreeWalkIter<DISCRIM, PlainTree, LLLinkedIter<PlainTree> > >
 679getWalkRange(PlainTree* node)
 680{
 681    typedef LLTreeWalkIter<DISCRIM, PlainTree, LLLinkedIter<PlainTree> > iter_type;
 682    typedef boost::iterator_range<iter_type> range_type;
 683    return range_type(iter_type(node,
 684                                PlainTree_child_begin,
 685                                PlainTree_child_end),
 686                      iter_type());
 687}
 688
 689// We could go through the exercise of writing EnhancedPlainTree containing
 690// root_range, getRootRange(), walk_range and getWalkRange() members -- but we
 691// won't. See EnhancedTreeNode for examples.
 692
 693/*****************************************************************************
 694*   Generic tree test data
 695*****************************************************************************/
 696template <class NODE>
 697typename LLPtrTo<NODE>::type example_tree()
 698{
 699    typedef typename LLPtrTo<NODE>::type NodePtr;
 700    NodePtr root(new NODE("root"));
 701    NodePtr A(root->newChild("A"));
 702    NodePtr A1(A->newChild("A1"));
 703/*  NodePtr A1a*/(A1->newChild("A1a"));
 704/*  NodePtr A1b*/(A1->newChild("A1b"));
 705/*  NodePtr A1c*/(A1->newChild("A1c"));
 706    NodePtr A2(A->newChild("A2"));
 707/*  NodePtr A2a*/(A2->newChild("A2a"));
 708/*  NodePtr A2b*/(A2->newChild("A2b"));
 709/*  NodePtr A2c*/(A2->newChild("A2c"));
 710    NodePtr A3(A->newChild("A3"));
 711/*  NodePtr A3a*/(A3->newChild("A3a"));
 712/*  NodePtr A3b*/(A3->newChild("A3b"));
 713/*  NodePtr A3c*/(A3->newChild("A3c"));
 714    NodePtr B(root->newChild("B"));
 715    NodePtr B1(B->newChild("B1"));
 716/*  NodePtr B1a*/(B1->newChild("B1a"));
 717/*  NodePtr B1b*/(B1->newChild("B1b"));
 718/*  NodePtr B1c*/(B1->newChild("B1c"));
 719    NodePtr B2(B->newChild("B2"));
 720/*  NodePtr B2a*/(B2->newChild("B2a"));
 721/*  NodePtr B2b*/(B2->newChild("B2b"));
 722/*  NodePtr B2c*/(B2->newChild("B2c"));
 723    NodePtr B3(B->newChild("B3"));
 724/*  NodePtr B3a*/(B3->newChild("B3a"));
 725/*  NodePtr B3b*/(B3->newChild("B3b"));
 726/*  NodePtr B3c*/(B3->newChild("B3c"));
 727    NodePtr C(root->newChild("C"));
 728    NodePtr C1(C->newChild("C1"));
 729/*  NodePtr C1a*/(C1->newChild("C1a"));
 730/*  NodePtr C1b*/(C1->newChild("C1b"));
 731/*  NodePtr C1c*/(C1->newChild("C1c"));
 732    NodePtr C2(C->newChild("C2"));
 733/*  NodePtr C2a*/(C2->newChild("C2a"));
 734/*  NodePtr C2b*/(C2->newChild("C2b"));
 735/*  NodePtr C2c*/(C2->newChild("C2c"));
 736    NodePtr C3(C->newChild("C3"));
 737/*  NodePtr C3a*/(C3->newChild("C3a"));
 738/*  NodePtr C3b*/(C3->newChild("C3b"));
 739/*  NodePtr C3c*/(C3->newChild("C3c"));
 740    return root;
 741}
 742
 743// WalkExpected<WalkIter> is the list of string node names we expect from a
 744// WalkIter traversal of our example_tree() data.
 745template <LLTreeIter::WalkIter DISCRIM>
 746struct WalkExpected: public Expected
 747{
 748    // Initialize with bad_strings: we don't expect to use this generic case,
 749    // only the specializations. Note that for a classic C-style array we must
 750    // pass a pair of iterators rather than extracting boost::begin() and
 751    // boost::end() within the target constructor: a template ctor accepts
 752    // these classic C-style arrays as char** rather than char*[length]. Oh well.
 753    WalkExpected(): Expected(boost::begin(bad_strings), boost::end(bad_strings)) {}
 754};
 755
 756// list of string node names we expect from traversing example_tree() in
 757// DFS_PRE order
 758const char* dfs_pre_strings[] =
 759{
 760    "root",
 761    "A",
 762    "A1",
 763    "A1a",
 764    "A1b",
 765    "A1c",
 766    "A2",
 767    "A2a",
 768    "A2b",
 769    "A2c",
 770    "A3",
 771    "A3a",
 772    "A3b",
 773    "A3c",
 774    "B",
 775    "B1",
 776    "B1a",
 777    "B1b",
 778    "B1c",
 779    "B2",
 780    "B2a",
 781    "B2b",
 782    "B2c",
 783    "B3",
 784    "B3a",
 785    "B3b",
 786    "B3c",
 787    "C",
 788    "C1",
 789    "C1a",
 790    "C1b",
 791    "C1c",
 792    "C2",
 793    "C2a",
 794    "C2b",
 795    "C2c",
 796    "C3",
 797    "C3a",
 798    "C3b",
 799    "C3c"
 800};
 801
 802// specialize WalkExpected<DFS_PRE> with the expected strings
 803template <>
 804struct WalkExpected<LLTreeIter::DFS_PRE>: public Expected
 805{
 806    WalkExpected(): Expected(boost::begin(dfs_pre_strings), boost::end(dfs_pre_strings)) {}
 807};
 808
 809// list of string node names we expect from traversing example_tree() in
 810// DFS_POST order
 811const char* dfs_post_strings[] =
 812{
 813    "A1a",
 814    "A1b",
 815    "A1c",
 816    "A1",
 817    "A2a",
 818    "A2b",
 819    "A2c",
 820    "A2",
 821    "A3a",
 822    "A3b",
 823    "A3c",
 824    "A3",
 825    "A",
 826    "B1a",
 827    "B1b",
 828    "B1c",
 829    "B1",
 830    "B2a",
 831    "B2b",
 832    "B2c",
 833    "B2",
 834    "B3a",
 835    "B3b",
 836    "B3c",
 837    "B3",
 838    "B",
 839    "C1a",
 840    "C1b",
 841    "C1c",
 842    "C1",
 843    "C2a",
 844    "C2b",
 845    "C2c",
 846    "C2",
 847    "C3a",
 848    "C3b",
 849    "C3c",
 850    "C3",
 851    "C",
 852    "root"
 853};
 854
 855// specialize WalkExpected<DFS_POST> with the expected strings
 856template <>
 857struct WalkExpected<LLTreeIter::DFS_POST>: public Expected
 858{
 859    WalkExpected(): Expected(boost::begin(dfs_post_strings), boost::end(dfs_post_strings)) {}
 860};
 861
 862// list of string node names we expect from traversing example_tree() in BFS order
 863const char* bfs_strings[] =
 864{
 865    "root",
 866    "A",
 867    "B",
 868    "C",
 869    "A1",
 870    "A2",
 871    "A3",
 872    "B1",
 873    "B2",
 874    "B3",
 875    "C1",
 876    "C2",
 877    "C3",
 878    "A1a",
 879    "A1b",
 880    "A1c",
 881    "A2a",
 882    "A2b",
 883    "A2c",
 884    "A3a",
 885    "A3b",
 886    "A3c",
 887    "B1a",
 888    "B1b",
 889    "B1c",
 890    "B2a",
 891    "B2b",
 892    "B2c",
 893    "B3a",
 894    "B3b",
 895    "B3c",
 896    "C1a",
 897    "C1b",
 898    "C1c",
 899    "C2a",
 900    "C2b",
 901    "C2c",
 902    "C3a",
 903    "C3b",
 904    "C3c"
 905};
 906
 907// specialize WalkExpected<BFS> with the expected strings
 908template <>
 909struct WalkExpected<LLTreeIter::BFS>: public Expected
 910{
 911    WalkExpected(): Expected(boost::begin(bfs_strings), boost::end(bfs_strings)) {}
 912};
 913
 914// extract a particular "arbitrary" node from the example_tree() data: the
 915// second (middle) node at each child level
 916template <class NODE, typename CHILDITER>
 917typename LLPtrTo<NODE>::type
 918get_B2b(const typename LLPtrTo<NODE>::type& root,
 919        const boost::function<CHILDITER(const typename LLPtrTo<NODE>::type&)>& child_begin)
 920{
 921    typedef typename LLPtrTo<NODE>::type NodePtr;
 922    CHILDITER Bi(child_begin(root));
 923    ++Bi;
 924    NodePtr B(*Bi);
 925    CHILDITER B2i(child_begin(B));
 926    ++B2i;
 927    NodePtr B2(*B2i);
 928    CHILDITER B2bi(child_begin(B2));
 929    ++B2bi;
 930    NodePtr B2b(*B2bi);
 931    return B2b;
 932}
 933
 934// RootExpected<RootIter> is the list of string node names we expect from a
 935// RootIter traversal of our example_tree() data.
 936template <LLTreeIter::RootIter DISCRIM>
 937struct RootExpected: public Expected
 938{
 939    // Initialize with bad_strings: we don't expect to use this generic case,
 940    // only the specializations.
 941    RootExpected(): Expected(boost::begin(bad_strings), boost::end(bad_strings)) {}
 942};
 943
 944// list of string node names we expect from traversing UP from
 945// example_tree()'s B2b node
 946const char* up_from_B2b[] =
 947{
 948    "B2b",
 949    "B2",
 950    "B",
 951    "root"
 952};
 953
 954// specialize RootExpected<UP> with the expected strings
 955template <>
 956struct RootExpected<LLTreeIter::UP>: public Expected
 957{
 958    RootExpected(): Expected(boost::begin(up_from_B2b), boost::end(up_from_B2b)) {}
 959};
 960
 961// list of string node names we expect from traversing DOWN to
 962// example_tree()'s B2b node
 963const char* down_to_B2b[] =
 964{
 965    "root",
 966    "B",
 967    "B2",
 968    "B2b"
 969};
 970
 971// specialize RootExpected<DOWN> with the expected strings
 972template <>
 973struct RootExpected<LLTreeIter::DOWN>: public Expected
 974{
 975    RootExpected(): Expected(boost::begin(down_to_B2b), boost::end(down_to_B2b)) {}
 976};
 977
 978/*****************************************************************************
 979*   Generic tree test functions
 980*****************************************************************************/
 981template<LLTreeIter::RootIter DISCRIM, class NODE, typename PARENTFUNC>
 982bool LLTreeRootIter_test(const std::string& itername, const std::string& nodename,
 983                         const typename LLPtrTo<NODE>::type& node,
 984                         PARENTFUNC parentfunc)
 985{
 986    std::ostringstream desc;
 987    desc << itername << '<' << nodename << "> from " << node->name();
 988    if (!  verify(desc.str(),
 989                  boost::make_iterator_range(LLTreeRootIter<DISCRIM, NODE>(node, parentfunc),
 990                                             LLTreeRootIter<DISCRIM, NODE>()),
 991                  RootExpected<DISCRIM>()))
 992        return false;
 993//  std::cout << desc.str() << '\n';
 994    // Try instantiating an iterator with NULL (that is, a default-constructed
 995    // node pointer). This test is less about "did we iterate once?" than "did
 996    // we avoid blowing up?"
 997    for (LLTreeRootIter<DISCRIM, NODE> hri = LLTreeRootIter<DISCRIM, NODE>(typename LLPtrTo<NODE>::type(), parentfunc), hrend;
 998         hri != hrend; /* ++hri */) // incrementing is moot, and MSVC complains
 999    {
1000//      std::cout << nodename << '(' << (*hri)->name() << ")\n";
1001        std::cout << itername << '<' << nodename << ">(NULL)\n";
1002        return false;
1003    }
1004    return true;
1005}
1006
1007template<class NODE, typename CHILDITER, typename PARENTFUNC, typename CHILDFUNC>
1008bool LLTreeUpIter_test(const std::string& nodename, PARENTFUNC parentfunc, CHILDFUNC childfunc)
1009{
1010    bool success = true;
1011    typedef typename LLPtrTo<NODE>::type ptr_type;
1012    ptr_type root(example_tree<NODE>());
1013    Cleanup<ptr_type> cleanup(root);
1014    ptr_type B2b(get_B2b<NODE, CHILDITER>(root, childfunc));
1015    if (! LLTreeRootIter_test<LLTreeIter::UP,   NODE>("LLTreeUpIter",   nodename, B2b, parentfunc))
1016        success = false;
1017    if (! LLTreeRootIter_test<LLTreeIter::DOWN, NODE>("LLTreeDownIter", nodename, B2b, parentfunc))
1018        success = false;
1019    return success;
1020}
1021
1022template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER,
1023          typename CHILDBEGINFUNC, typename CHILDENDFUNC>
1024bool LLTreeWalkIter_test(const std::string& itername, const std::string& nodename,
1025                      CHILDBEGINFUNC childbegin, CHILDENDFUNC childend)
1026{
1027    typename LLPtrTo<NODE>::type root(example_tree<NODE>());
1028    Cleanup<typename LLPtrTo<NODE>::type> cleanup(root);
1029    std::ostringstream desc;
1030    desc << itername << '<' << nodename << "> from " << root->name();
1031    if (!  verify(desc.str(),
1032                  boost::make_iterator_range(LLTreeWalkIter<DISCRIM, NODE, CHILDITER>(root,
1033                                                                                      childbegin,
1034                                                                                      childend),
1035                                             LLTreeWalkIter<DISCRIM, NODE, CHILDITER>()),
1036                  WalkExpected<DISCRIM>()))
1037        return false;
1038    // Try instantiating an iterator with NULL (that is, a default-constructed
1039    // node pointer). This test is less about "did we iterate once?" than "did
1040    // we avoid blowing up?"
1041    for (LLTreeWalkIter<DISCRIM, NODE, CHILDITER> twi = LLTreeWalkIter<DISCRIM, NODE, CHILDITER>(typename LLPtrTo<NODE>::type(),
1042                                                      childbegin,
1043                                                      childend),
1044                                                  twend;
1045         twi != twend; /* ++twi */) // incrementing is moot, and MSVC complains
1046    {
1047        std::cout << itername << '<' << nodename << ">(NULL)\n";
1048        return false;
1049    }             
1050    return true;
1051}
1052
1053template <class NODE, typename CHILDITER,
1054          typename PARENTFUNC, typename CHILDBEGINFUNC, typename CHILDENDFUNC>
1055bool LLTreeIter_tests(const std::string& nodename,
1056                      PARENTFUNC parentfunc, CHILDBEGINFUNC childbegin, CHILDENDFUNC childend)
1057{
1058    bool success = true;
1059    if (! LLTreeUpIter_test<NODE, CHILDITER>(nodename, parentfunc, childbegin))
1060        success = false;
1061/*==========================================================================*|
1062    LLTreeIter_test<NODE, LLTreeDFSIter<NODE, CHILDITER> >("LLTreeDFSIter", nodename,
1063                                                           childbegin, childend);
1064    LLTreeIter_test<NODE, LLTreeDFSPostIter<NODE, CHILDITER> >("LLTreeDFSPostIter", nodename,
1065                                                               childbegin, childend);
1066    LLTreeIter_test<NODE, LLTreeBFSIter<NODE, CHILDITER> >("LLTreeBFSIter", nodename,
1067                                                           childbegin, childend);
1068|*==========================================================================*/
1069    if (! LLTreeWalkIter_test<LLTreeIter::DFS_PRE,  NODE, CHILDITER>("LLTreeDFSIter", nodename,
1070                                                                     childbegin, childend))
1071        success = false;
1072    if (! LLTreeWalkIter_test<LLTreeIter::DFS_POST, NODE, CHILDITER>("LLTreeDFSPostIter", nodename,
1073                                                                     childbegin, childend))
1074        success = false;
1075    if (! LLTreeWalkIter_test<LLTreeIter::BFS,      NODE, CHILDITER>("LLTreeBFSIter", nodename,
1076                                                                     childbegin, childend))
1077        success = false;
1078    return success;
1079}
1080
1081namespace tut
1082{
1083    template<> template<>
1084    void iter_object::test<3>()
1085    {
1086//      set_test_name("LLTreeIter tests");
1087        ensure(LLTreeIter_tests<TreeNode, TreeNode::child_iterator>
1088                               ("TreeNode",
1089                                boost::bind(&TreeNode::getParent, _1),
1090                                boost::bind(&TreeNode::child_begin, _1),
1091                                boost::bind(&TreeNode::child_end, _1)));
1092        ensure(LLTreeIter_tests<PlainTree, LLLinkedIter<PlainTree> >
1093                               ("PlainTree",
1094                                boost::bind(&PlainTree::mParent, _1),
1095                                PlainTree_child_begin,
1096                                PlainTree_child_end));
1097    }
1098
1099    template<> template<>
1100    void iter_object::test<4>()
1101    {
1102//      set_test_name("getRootRange() tests");
1103        // This test function illustrates the looping techniques described in the
1104        // comments for the getRootRange() free function, the
1105        // EnhancedTreeNode::root_range template and the
1106        // EnhancedTreeNode::getRootRange() method. Obviously the BOOST_FOREACH()
1107        // forms are more succinct.
1108        TreeNodePtr tnroot(example_tree<TreeNode>());
1109        TreeNodePtr tnB2b(get_B2b<TreeNode, TreeNode::child_iterator>
1110                          (tnroot, boost::bind(&TreeNode::child_begin, _1)));
1111    
1112        std::string desc1("BOOST_FOREACH(TreeNodePr, getRootRange<LLTreeIter::UP>(tnB2b))");
1113//      std::cout << desc1 << "\n";
1114        // Although we've commented out the output statement, ensure that the
1115        // loop construct is still valid, as promised by the getRootRange()
1116        // documentation.
1117        BOOST_FOREACH(TreeNodePtr node, getRootRange<LLTreeIter::UP>(tnB2b))
1118        {
1119//          std::cout << node->name() << '\n';
1120        }
1121        ensure(desc1,
1122               verify(desc1, getRootRange<LLTreeIter::UP>(tnB2b), RootExpected<LLTreeIter::UP>()));
1123
1124        EnhancedTreeNodePtr etnroot(example_tree<EnhancedTreeNode>());
1125        EnhancedTreeNodePtr etnB2b(get_B2b<EnhancedTreeNode, EnhancedTreeNode::child_iterator>
1126                                   (etnroot, boost::bind(&EnhancedTreeNode::child_begin, _1)));
1127
1128//      std::cout << "EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type range =\n"
1129//                << "    etnB2b->getRootRange<LLTreeIter::DOWN>();\n"
1130//                << "for (EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type::iterator ri = range.begin();\n"
1131//                << "     ri != range.end(); ++ri)\n";
1132        EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type range =
1133            etnB2b->getRootRange<LLTreeIter::DOWN>();
1134        for (EnhancedTreeNode::root_range<LLTreeIter::DOWN>::type::iterator ri = range.begin();
1135             ri != range.end(); ++ri)
1136        {
1137//          std::cout << (*ri)->name() << '\n';
1138        }
1139
1140        std::string desc2("BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange<LLTreeIter::UP>())");
1141//      std::cout << desc2 << '\n';
1142        BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange<LLTreeIter::UP>())
1143        {
1144//          std::cout << node->name() << '\n';
1145        }
1146        ensure(desc2,
1147               verify(desc2, etnB2b->getRootRange<LLTreeIter::UP>(), RootExpected<LLTreeIter::UP>()));
1148    }
1149
1150    template<> template<>
1151    void iter_object::test<5>()
1152    {
1153//      set_test_name("getWalkRange() tests");
1154        // This test function doesn't illustrate the looping permutations for
1155        // getWalkRange(); see getRootRange_tests() for such examples. This
1156        // function simply verifies that they all work.
1157
1158        // TreeNode, using helper function
1159        TreeNodePtr tnroot(example_tree<TreeNode>());
1160        std::string desc_tnpre("getWalkRange<LLTreeIter::DFS_PRE>(tnroot)");
1161        ensure(desc_tnpre,
1162               verify(desc_tnpre,
1163                      getWalkRange<LLTreeIter::DFS_PRE>(tnroot),
1164                      WalkExpected<LLTreeIter::DFS_PRE>()));
1165        std::string desc_tnpost("getWalkRange<LLTreeIter::DFS_POST>(tnroot)");
1166        ensure(desc_tnpost,
1167               verify(desc_tnpost,
1168                      getWalkRange<LLTreeIter::DFS_POST>(tnroot),
1169                      WalkExpected<LLTreeIter::DFS_POST>()));
1170        std::string desc_tnb("getWalkRange<LLTreeIter::BFS>(tnroot)");
1171        ensure(desc_tnb,
1172               verify(desc_tnb,
1173                      getWalkRange<LLTreeIter::BFS>(tnroot),
1174                      WalkExpected<LLTreeIter::BFS>()));
1175
1176        // EnhancedTreeNode, using method
1177        EnhancedTreeNodePtr etnroot(example_tree<EnhancedTreeNode>());
1178        std::string desc_etnpre("etnroot->getWalkRange<LLTreeIter::DFS_PRE>()");
1179        ensure(desc_etnpre,
1180               verify(desc_etnpre,
1181                      etnroot->getWalkRange<LLTreeIter::DFS_PRE>(),
1182                      WalkExpected<LLTreeIter::DFS_PRE>()));
1183        std::string desc_etnpost("etnroot->getWalkRange<LLTreeIter::DFS_POST>()");
1184        ensure(desc_etnpost,
1185               verify(desc_etnpost,
1186                      etnroot->getWalkRange<LLTreeIter::DFS_POST>(),
1187                      WalkExpected<LLTreeIter::DFS_POST>()));
1188        std::string desc_etnb("etnroot->getWalkRange<LLTreeIter::BFS>()");
1189        ensure(desc_etnb,
1190               verify(desc_etnb,
1191                      etnroot->getWalkRange<LLTreeIter::BFS>(),
1192                      WalkExpected<LLTreeIter::BFS>()));
1193
1194        // PlainTree, using helper function
1195        PlainTree* ptroot(example_tree<PlainTree>());
1196        Cleanup<PlainTree*> cleanup(ptroot);
1197        std::string desc_ptpre("getWalkRange<LLTreeIter::DFS_PRE>(ptroot)");
1198        ensure(desc_ptpre,
1199               verify(desc_ptpre,
1200                      getWalkRange<LLTreeIter::DFS_PRE>(ptroot),
1201                      WalkExpected<LLTreeIter::DFS_PRE>()));
1202        std::string desc_ptpost("getWalkRange<LLTreeIter::DFS_POST>(ptroot)");
1203        ensure(desc_ptpost,
1204               verify(desc_ptpost,
1205                      getWalkRange<LLTreeIter::DFS_POST>(ptroot),
1206                      WalkExpected<LLTreeIter::DFS_POST>()));
1207        std::string desc_ptb("getWalkRange<LLTreeIter::BFS>(ptroot)");
1208        ensure(desc_ptb,
1209               verify(desc_ptb,
1210                      getWalkRange<LLTreeIter::BFS>(ptroot),
1211                      WalkExpected<LLTreeIter::BFS>()));
1212    }
1213} // tut