// test_iterJava.cpp (c) 2009 adolfo@di-mare.com

/** \file  test_iterJava.cpp
    \brief Test ==> class iterJava<>.

    \author Adolfo Di Mare <adolfo@di-mare.com>
    \date   2009

    - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04
*/

#include "iterJava.h"
#include "str2list.h"
#include "BUnit.h"
#include <list>

/// Test ==> \c iterJava<>.
class test_iterJava : public TestCase {
public:
    bool run();
private:
    void test_example();
    void test_const_example();
    void test_examplePtr();
    void test_assign();
    void test_set_CCC();
    void test_next();
    void test_erase();
    void test_palindrome();
    void test_palindromo();
    void test_setReverse();
    void test_isPalindrome();
    void test_Tree_BF();
    void test_Tree_PLR();
    void test_Tree_LPR();
    void test_Tree_LRP();
}; // test_iterJava

/// Test ==> \c iterJava<> ==> \c run().
bool test_iterJava::run() {
    test_example();
    test_const_example();
    test_examplePtr();
    test_assign();
    test_set_CCC();
    test_next();
    test_erase();
    test_palindrome();
    test_palindromo();
    test_setReverse();
    test_isPalindrome();
    test_Tree_BF();
    test_Tree_PLR();
    test_Tree_LPR();
    test_Tree_LRP();
    return wasSuccessful();
}

std::list<long> makeList_long(const char* V); // forward declaration

/// Test ==> \c iterJava<> ==> \c example().
void test_iterJava::test_example() {
    {{  // test::example()
        std::list<long> Lfwd, Lbck, L;
        assertTrue( Lfwd.empty() && L.empty() );
        L = makeList_long( "( 1 2 3 4 5 )" );
        iterJava< std::list<long>::iterator > itFwd( L.begin(), L.end() );
        iterJava< std::list<long>::iterator > itBck( L.begin(), L.end() );
        itBck.setReverse();
        while ( itFwd.hasNext() && itBck.hasNext() ) {
            Lfwd.push_back( itFwd.next() );
            Lbck.push_back( itBck.next() );
        }
        assertTrue( Lfwd == makeList_long( "( 1 2 3 4 5 )" ) );
        assertTrue( Lbck == makeList_long( "( 5 4 3 2 1 )" ) );
    }}
    {   std::list<long> Lcp, L;
        {   // L.empty()
            L = makeList_long( "" );
            iterJava< std::list<long>::iterator > iter( L.begin(), L.end() );
            assertTrue( ! iter.hasNext() );
        }
        {   // L.size() == 1
            L = makeList_long( " 1 " );
            iterJava< std::list<long>::iterator > iter( L.begin(), L.end() );
            assertTrue( iter.hasNext() );
            assertTrue( iter.next() == 1 );
            assertTrue( ! iter.hasNext() );
        }
        {   // L.size() == 2
            L = makeList_long( " 1 2 " );
            iterJava< std::list<long>::iterator > iter( L.begin(), L.end() );
            assertTrue( iter.hasNext() );
            assertTrue( iter.next() == 1 );
            assertTrue( iter.hasNext() );
            assertTrue( iter.next() == 2 );
            assertTrue( ! iter.hasNext() );
            iter.set( L );
            assertTrue( iter.next() == 1 );
            L.erase(iter);
            assertTrue( iter.next() == 2 );
            assertTrue( ! iter.hasNext() );
        }
        {   // L.empty()
            std::list<long> Lcp;
            L = makeList_long( " 5 4 3 2 1 " );
            iterJava< std::list<long>::iterator > iter( L.begin(), L.end() );
            iter.setReverse();
            while ( iter.hasNext() ) {
                Lcp.push_back( iter.next() );
            }
            assertTrue( Lcp == makeList_long( "( 1 2 3 4 5 )" ) );
        }
    }
}

/// Test ==> \c iterJava<> ==> \c examplePtr().
void test_iterJava::test_examplePtr() {
    {{  // test::examplePtr()
        #define dim(V) ( sizeof(V)/sizeof(*V) )
        std::list<long> L;
        int VEC[] = { 1, 2, 3, 4, 5 };
        iterJava< int* > iter( VEC, VEC+dim(VEC) );
        while ( iter.hasNext() ) {
            L.push_back( iter.next() );
        }
        assertTrue( L == makeList_long( "( 1 2 3 4 5 )" ) );
    }}
    #undef  dim
}

/// Test ==> \c iterJava<> ==> \c const_example().
void test_iterJava::test_const_example() {
    #ifdef const_error
        #warning Macro [const_error] already defined
    #endif
    {{  // test::const_example()
        #define const_error
        #undef  const_error
        std::list<long> Lcp, L;
        assertTrue( Lcp.empty() );
        L = makeList_long( "( 1 2 3 4 5 )" );
        iterJava< std::list<long>::const_iterator > iter( L.begin(),L.end() );
        while ( iter.hasNext() ) {
            Lcp.push_back( iter.next() );
            #ifdef const_error
                L.erase(iter); // forbidden for const_iterator
            #endif
        }
        assertTrue( L == Lcp );
        iterJava< std::list<long>::const_iterator > IT = iter;
        assertTrue( IT == iter && !( IT.hasNext() ) && !( IT != iter ) );
        #undef  const_error
    }}
    {   // const list<>&
        std::list<long> Lcp, L;
        assertTrue( Lcp.empty() );
        L = longlist( "( 1 2 3 4 5 )" );
        const std::list<long> & L_const = L;
        iterJava< std::list<long>::const_iterator > iter( L_const.begin(),L_const.end() );
        while ( iter.hasNext() ) {
            Lcp.push_back( iter.next() );
        }
        assertTrue( L == Lcp );
        iterJava< std::list<long>::const_iterator > IT = iter;
        assertTrue( IT == iter && !( IT.hasNext() ) && !( IT != iter ) );
    }
}

#include <cassert>

#ifdef English_dox
/// Implementation to show that const_iterator cannot be used to erase values.
#endif
#ifdef Spanish_dox
/// Implementación en la que se muestra que un \c const_iterator no se puede usar para eliminar valores.
#endif
void const_compile_error( std::list<long> &L ) {
    typedef iterJava< std::list<long>::const_iterator > Iter;
    Iter iter( L.begin(),L.end() );
        while ( iter.hasNext() ) {
        //  L.erase(iter); // forbidden for const_iterator
        }
        assert( L.empty() );
}

template <typename C>
bool isPalindrome( const C& CCC );

/// Test ==> \c iterJava<> ==> \c isPalindrome().
void test_iterJava::test_isPalindrome() {
    {{  // test::isPalindrome()
        assertFalse( isPalindrome( makeList_long( "( 1 2 3 4 5 )" ) ) );
        assertTrue(  isPalindrome( makeList_long( "( 1 2 3 2 1 )" ) ) );
        assertTrue(  isPalindrome( makeList_long( "( 1 )" ) ) );
        assertTrue(  isPalindrome( makeList_long( "( 1 2 1 )" ) ) );
        assertTrue(  isPalindrome( makeList_long( "( )" ) ) );
    }}
}

/// Test ==> \c iterJava<> ==> \c palindrome().
void test_iterJava::test_palindrome() {
    {{  // test::palindrome()
        std::list<long> L = makeList_long( "( 1 2 3 2 1 )" );
        typedef std::list<long>::const_iterator IterFwd;
        typedef std::reverse_iterator<IterFwd> IterBck;

        iterJava< IterFwd > itFwd( L.begin(),  L.end()  );
        iterJava< IterBck > itBck( L.rbegin(), L.rend() );

        while ( itFwd.hasNext() && itBck.hasNext() ) {
            if ( itFwd.next() != itBck.next() ) {
                assertTrue( "palindrome error" &&  false );
            }
        }
        assertTrue( !itFwd.hasNext() && !itBck.hasNext() );
    }}
    {
        std::list<long> L = makeList_long( "( 1 2 3 2 1 )" );
        typedef std::list<long>::const_iterator Iter;
        iterJava< Iter > itFwd, itBck;
        itFwd.set(L);
        itBck.set(L); itBck.setReverse();
        while ( itFwd.hasNext() && itBck.hasNext() ) {
            if ( itFwd.next() != itBck.next() ) {
                assertTrue( "palindrome error" && false );
            }
        }
        assertTrue( !itFwd.hasNext() && !itBck.hasNext() );
    }
}

/// Test ==> \c iterJava<> ==> \c setReverse().
void test_iterJava::test_setReverse() {
    {{  // test::setReverse()
        std::list<long> L = makeList_long( "( 1 2 3 4 5 )" );
        typedef std::list<long>::const_iterator Iter;
        iterJava< Iter > itFwd, itBck;
        itFwd.set(L);
        assertTrue( itFwd.next() == 1 ); // next() !
        itFwd.setReverse();              // NOP !!!
        assertTrue( itFwd.isForward() );

        itBck.set(L); itBck.setReverse();
        assertTrue( !itBck.isForward() );
        assertTrue(  itBck.isBackward() && itBck.isReverse() );
        assertTrue(  itBck.next() == 5 );

        itFwd.set(L); itFwd.setReverse();
        assertTrue( ! itFwd.isForward() && itFwd.isReverse() );
    }}
    {
    }
}

#if 1
    template <typename C> bool isPalindrome( const C& CCC ) {{
        typedef typename C::const_iterator Iter;
        iterJava< Iter > itFwd, itBck;
        itFwd.set(CCC);
        itBck.set(CCC); itBck.setReverse();
        while ( itFwd.hasNext() && itBck.hasNext() ) {
            if ( itFwd.next() != itBck.next() ) {
                return false;
            }
        }
        return ( !itFwd.hasNext() && !itBck.hasNext() );
    }}
#else
    template <typename C>
    bool isPalindrome( const C& CCC ) {{
        typedef typename C::const_iterator     IterFwd;
        typedef typename std::reverse_iterator<IterFwd> IterBck;

        iterJava< IterFwd > itFwd( CCC.begin(),  CCC.end()  );
        iterJava< IterBck > itBck( CCC.rbegin(), CCC.rend() );

        while ( itFwd.hasNext() && itBck.hasNext() ) {
            if ( itFwd.next() != itBck.next() ) {
                return false;
            }
        }
        return ( !itFwd.hasNext() && !itBck.hasNext() );
    }}
#endif

#ifdef English_dox
/**
    \fn isPalindrome( const C& CCC )
    Returns \c true when \c CCC is a palindrome.
    - Traversing a palindrome forward yields the same
      secuence of values as traversing it backwards.

    \dontinclude test_iterJava.cpp
    \skipline    test::palindrome()
    \until       }}

    \dontinclude test_iterJava.cpp
    \skipline    isPalindrome( const C& CCC ) {{
    \until       }}

    \dontinclude test_iterJava.cpp
    \skipline    test::isPalindrome()
    \until       }}
    \see         test_iterJava::test_palindrome()
    \see         test_iterJava::test_isPalindrome()
*/
#endif
#ifdef Spanish_dox
/**
\fn isPalindrome( const C& CCC )
    Retorna \c true si \c CCC es un palíndromo.
    - Al recorrer un palíndromo hacia adelante se obtienen
    los mismo valors que al recorrerlo hacia atrás.

    \dontinclude test_iterJava.cpp
    \skipline    test::palindrome()
    \until       }}

    \dontinclude test_iterJava.cpp
    \skipline    isPalindrome( const C& CCC ) {{
    \until       }}

    \dontinclude test_iterJava.cpp
    \skipline    test::isPalindrome()
    \until       }}
    \see         test_iterJava::test_palindrome()
    \see         test_iterJava::test_isPalindrome()
*/
#endif

/// Test ==> \c iterJava<> ==> \c palindrome().
void test_iterJava::test_palindromo() {
    bool palindromo(const std::list< std::string >& L);
    {{  // test::palindromo()
        assertTrue(  palindromo( str2list( "[ 1 2 3 2 1 ]") ) );
        assertFalse( palindromo( str2list( "[ 1 2 3 2 0 ]") ) );
        assertTrue(  palindromo( str2list( "[ r a d a r ]") ) );
        assertFalse( palindromo( str2list( "[ M A J E M ]") ) );
    }}
}

/** Regresa true si al recorrer el contenedor "L" hacia adelante se obtiene
    el mismo resultado que al recorrerlo hacia atrás.
    Un palíndromo es una palabra que se lee igual al derecho que al revés.

    \dontinclude test_iterJava.cpp
    \skipline    test::palindromo()
    \until       }}
*/
bool palindromo(const std::list< std::string >& L) {
    return isPalindrome(L);
}

/// Test ==> \c iterJava<> ==> \c next().
void test_iterJava::test_next() {
    {{  // test::next()
        std::list<long> L = makeList_long( "( 1 2 3 4 5 )" );
        iterJava< std::list<long>::iterator > iter( L.begin(), L.end() );
        int  trngl = 3;
        while ( iter.hasNext() ) {
            switch (trngl++ % 3) {
                case 0: { // reference
                    long & l = iter.next(); l++;
                    break;
                }
                case 1: { // pointer
                    long * p = & iter.next(); (*p)++;
                    break;
                }
                case 2: { // direct
                    iter.next()++;
                    break;
                }
            }
        }
        assertTrue( L == makeList_long( "( 2 3 4 5 6 )" ) );
    }}
    if (false) { // cannot erase with 2 iterators over the same container
        std::list<long> L = makeList_long( "( 1 2 3 4 5 )" );
        iterJava< std::list<long>::iterator > itFwd( L.begin(), L.end() );
        iterJava< std::list<long>::iterator > itBck( L.begin(), L.end() );
        itBck.setReverse(); int n=0;
        while ( itFwd.hasNext() && itBck.hasNext() ) {
            ++n;
            L.push_back( itFwd.next() );
            L.push_back( itBck.next() );
            if ( itFwd.current() == itBck.current() ) {
                break;
            }
            L.erase(itFwd);
            L.erase(itBck);
        }
        assertTrue( L.size() != 7 );
        assertTrue( n == 3 );
        assertTrue( itFwd.next() == 3 );
        assertTrue( itBck.next() == 3 );
    }
}

/// Test ==> \c iterJava<> ==> \c set(CCC).
void test_iterJava::test_set_CCC() {
    {{  // test::set_CCC()
        std::list<long> L1 = makeList_long( "( 1 2 3 4 5 )" );
        std::list<long> L2 = makeList_long( "( 6 7 8 9 )" );
        iterJava< std::list<long>::iterator > iter( L1.begin(), L1.end() );
        int i = 0;
        while ( iter.hasNext() ) { // L1
            i++; assertTrue( i == iter.next() );
            L1.erase( iter );
        }
        iter.set( L2 );
        while ( iter.hasNext() ) { // L2
            i++; assertTrue( i == iter.next() );
        }
        assertTrue( L1.empty() );
    }}
    {   // same but reversed
        std::list<long> L1 = makeList_long( "( 1 2 3 4 5 )" );
        std::list<long> L2 = makeList_long( "( 6 7 8 9 )" );
        iterJava< std::list<long>::iterator > iter;
        iter.set( L2 ); iter.setReverse();
        int i = 10;
        while ( iter.hasNext() ) { // L2
            i--; assertTrue( i == iter.next() );
        }
        iter.set( L1 ); iter.setReverse();
        while ( iter.hasNext() ) { // L1
            i--; assertTrue( i == iter.next() );
        }
    }
}

/// Test ==> \c iterJava<> ==> \c assign(CCC).
void test_iterJava::test_assign() {
    {{  // test::assign()
        std::list<long> L, Lcp;
        L = makeList_long( "( 1 2 3 4 5 )" );
        iterJava< std::list<long>::const_iterator > iter123;
        iterJava< std::list<long>::const_iterator > iter45;
        iter123.set( L.begin(), L.end() ); // full range
        int i=1;
        while ( i<=3 ) {
            assertTrue( i == iter123.next() );
            Lcp.push_back( i );
            ++i;
        }
        iter45 = iter123; // iter45 <==> iter123
        while ( i<=5 ) {
            assertTrue( i == iter45.next() );
            Lcp.push_back( i );
            ++i;
        }
        assertTrue( Lcp == makeList_long( "( 1 2 3 4 5 )" ) );
    }}
    {   // non-const test
        std::list<long> L, Lcp;
        L = makeList_long( "( 1 2 3 4 5 )" );
        iterJava< std::list<long>::iterator > iter123;
        iterJava< std::list<long>::iterator > iter45;
        iter123.set( L.begin(), L.end() ); // full range
        int i=1;
        while ( i<=3 ) {
            assertTrue( i == iter123.next() );
            Lcp.push_back( i );
            L.erase( iter123 );
            ++i;
        }
        iter45 = iter123;
        while ( i<=5 ) {  // iter45 <==> iter123
            assertTrue( i == iter45.next() );
            Lcp.push_back( i );
            L.erase( iter45 );
            ++i;
        }
        assertTrue( Lcp == makeList_long( "( 1 2 3 4 5 )" ) );
        assertTrue( L.empty() );
    }
}

/// Test ==> \c iterJava<> ==> \c erase().
void test_iterJava::test_erase() {
    {{  // test::erase()
        std::list<long> L = makeList_long( "( 1 2 3 4 5 )" );
        iterJava< std::list<long>::iterator > iter( L.begin(), L.end() );
        int i = 0;
        while ( iter.hasNext() ) {
            assertTrue( ! L.empty() );
            long *pL = & iter.next(); i++;
            assertTrue( i == *pL );
            L.erase( iter ); // L.erase( iter.current() );
        }
        assertTrue( L.empty() );
    }}
    {
    }
}

#include "Tree_BF.h" // test multiple inclusion
#include "Tree_LRP.h"
#include "Tree_LPR.h"
#include "Tree_PLR.h"

#include "Tree_BF.h"
#include "Tree_LRP.h"
#include "Tree_LPR.h"
#include "Tree_PLR.h"

/// Test ==> \c iterJava<> ==> \c Tree_BF().
void test_iterJava::test_Tree_BF() {
    void make_a_o(TL::Tree<char> & T); // forward declaration
    {{  // test::Tree_BF()
        TL::Tree<char> T;     make_a_o(T);
        Tree_BF<char>  iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "abcdefghijklmno" && "Tree_BF" );
    }}
    if (false) {   // T.empty() && 1 == T.Count()
        TL::Tree<char> T;
        Tree_BF<char>  iter;
        iter.set(T);
        assertTrue( ! iter.hasNext() && "Tree_BF" );
        T = 'A';
        iter.set(T);
        assertTrue( iter.hasNext() && "Tree_BF" );
        assertTrue( 'A' == iter.next().Data() && "Tree_BF" );
        assertTrue( ! iter.hasNext() && "Tree_BF" );
    }
    {
        TL::Tree<char> T;
        Tree_BF<char>  iter;   std::string L;
        T = 'A';
        T.Change_Child(1,'1');
        T.Child(1).Change_Child(2,'2');
        T.Child(1).Child(2).Change_Child(3,'3');
        iter.set(T); L.clear();
        while ( iter.hasNext() ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "A123" && "Tree_BF" );
    }
    //  T = 0
    //    ./ \.
    //    1   2
    //  ./ \ / \.
    //   3 4 5 6
    void make_0_6(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_0_6(T);
        Tree_BF<char>  iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "0123456" && "Tree_BF" );
    }
    //   T = F
    //     ./ \.
    //     B   G
    //   ./ \   \.
    //   A   D   I
    // ./ \     /.
    // C   E   H
    void make_A_H(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_A_H(T);
        Tree_BF<char>  iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "FBGADICEH" && "Tree_BF" );
    }
    //     T = A
    //       ./ \.
    //      ./   \.
    //     ./     \.
    //     B       C
    //   ./ \     / \.
    //   D   E   F   G
    // ./ \ / \ / \ / \.
    //  H I J K L M N O
    void make_A_O(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_A_O(T);
        Tree_BF<char>  iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "ABCDEFGHIJKLMNO" && "Tree_BF" );
    }
}

/// Test ==> \c iterJava<> ==> \c Tree_PLR().
void test_iterJava::test_Tree_PLR() {
    void make_a_o(TL::Tree<char> & T);
    {{  // test::Tree_PLR()
        TL::Tree<char> T;     make_a_o(T);
        Tree_PLR<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "abfghcdeijlmnok" && "Tree_PLR" );
    }}
    if (true) {   // T.empty() && 1 == T.Count()
        TL::Tree<char> T;
        Tree_PLR<char>  iter;
        iter.set(T);
        assertTrue( ! iter.hasNext() && "Tree_PLR" );
        T = 'A';
        iter.set(T);
        assertTrue( iter.hasNext() && "Tree_PLR" );
        assertTrue( 'A' == iter.next().Data() && "Tree_PLR" );
        assertTrue( ! iter.hasNext() && "Tree_PLR" );
    }
    //  T = 0
    //    ./ \.
    //    1   2
    //  ./ \ / \.
    //   3 4 5 6
    void make_0_6(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_0_6(T);
        Tree_PLR<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "0134256" && "Tree_PLR" );
    }
    //   T = F
    //     ./ \.
    //     B   G
    //   ./ \   \.
    //   A   D   I
    // ./ \     /.
    // C   E   H
    void make_A_H(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_A_H(T);
        Tree_PLR<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "FBACEDGIH" && "Tree_PLR" );
    }
    //     T = A
    //       ./ \.
    //      ./   \.
    //     ./     \.
    //     B       C
    //   ./ \     / \.
    //   D   E   F   G
    // ./ \ / \ / \ / \.
    //  H I J K L M N O
    void make_A_O(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_A_O(T);
        Tree_PLR<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "ABDHIEJKCFLMGNO" && "Tree_PLR" );
    }
}

/// Test ==> \c iterJava<> ==> \c Tree_LPR().
void test_iterJava::test_Tree_LPR() {
    void make_a_o(TL::Tree<char> & T);
    {{  // test::Tree_LPR()
        TL::Tree<char> T;     make_a_o(T);
        Tree_LPR<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "fbghacdieljnmok"  && "Tree_LPR" );
    }}
    if (false) {   // T.empty() && 1 == T.Count() // WABE !!!
        TL::Tree<char> T;
        Tree_LPR<char>  iter;
        iter.set(T);
        assertTrue( ! iter.hasNext() && "Tree_LPR" );
        T = 'A';
        iter.set(T);
        assertTrue( iter.hasNext() && "Tree_LPR" );
        assertTrue( 'A' == iter.next().Data() && "Tree_LPR" );
        assertTrue( ! iter.hasNext() && "Tree_LPR" );
    }
    //  T = 0
    //    ./ \.
    //    1   2
    //  ./ \ / \.
    //   3 4 5 6
    void make_0_6(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_0_6(T);
        Tree_LPR<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "3140526"  && "Tree_LPR" );
        assertTrue( L != "314526"   && "Tree_LPR [T.Root() missing]" );
    }
    //   T = F
    //     ./ \.
    //     B   G
    //   ./ \   \.
    //   A   D   I
    // ./ \     /.
    // C   E   H
    void make_A_H(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_A_H(T);
        assertTrue( check_ok(T) );
        Tree_LPR<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "CAEBDFGHI" && "Tree_LPR" );
        assertTrue( L != "CAEDHI" && "Tree_LPR [ BFG missing ]" );
        assertTrue( L != "CAEBDFGHIH" && "Tree_LPR [Extra H]" );
        assertTrue( L != "CAEBDFG" && "Tree_LPR [ HI missing ]" );
    }
    //     T = A
    //       ./ \.
    //      ./   \.
    //     ./     \.
    //     B       C
    //   ./ \     / \.
    //   D   E   F   G
    // ./ \ / \ / \ / \.
    //  H I J K L M N O
    void make_A_O(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_A_O(T);
        Tree_LPR<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "HDIBJEKALFMCNGO"  && "Tree_LPR" );
        assertTrue( L != "HDIJEKLFMNGO"     && "Tree_LPR [ BAC missing ]" );
    }
}

/// Test ==> \c iterJava<> ==> \c Tree_LRP().
void test_iterJava::test_Tree_LRP() {
    void make_a_o(TL::Tree<char> & T);
    {{  // test::Tree_LRP()
        TL::Tree<char> T;     make_a_o(T);
        Tree_LRP<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "fghbcdilnomjkea"  && "Tree_LRP" );
    }}
    if (false) {   // T.empty() && 1 == T.Count() // WABE !!!
        TL::Tree<char> T;
        Tree_LRP<char>  iter;
        iter.set(T);
        assertTrue( ! iter.hasNext() && "Tree_LRP" );
        T = 'A';
        iter.set(T);
        assertTrue( iter.hasNext() && "Tree_LRP" );
        assertTrue( 'A' == iter.next().Data() && "Tree_LRP" );
        assertTrue( ! iter.hasNext() && "Tree_LRP" );
    }
    //  T = 0
    //    ./ \.
    //    1   2
    //  ./ \ / \.
    //   3 4 5 6
    void make_0_6(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_0_6(T);
        Tree_LRP<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "3415620"  && "Tree_LRP" );
    }
    //   T = F
    //     ./ \.
    //     B   G
    //   ./ \   \.
    //   A   D   I
    // ./ \     /.
    // C   E   H
    void make_A_H(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_A_H(T);
        Tree_LRP<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "CEADBHIGF" && "Tree_LRP [Wabe]" );
        assertTrue( L != "CEADBHIF"  && "Tree_LRP [ G missing ]" );
    }
    //     T = A
    //       ./ \.
    //      ./   \.
    //     ./     \.
    //     B       C
    //   ./ \     / \.
    //   D   E   F   G
    // ./ \ / \ / \ / \.
    //  H I J K L M N O
    void make_A_O(TL::Tree<char> & T); // forward declaration
    {
        TL::Tree<char> T;     make_A_O(T);
        Tree_LRP<char> iter;  std::string L;
        iter.set(T);
        while ( iter.hasNext()  ) {
            TL::Tree<char> S = iter.next();
            L.push_back( *S );
        }
        assertTrue( L == "HIDJKEBLMFNOGCA"  && "Tree_LRP [Wabe]" );
        assertTrue( L != "HIDJKEBLMFNOGA"   && "Tree_LRP [ C missing ]" );
     }
}

/** <code>T = ( a ( b ( f g h ) c d e ( i j ( l m  ( n o ) ) k ) )</code>.
    \code
                 T = a
                     |--b
                     |  |--f
     T = a           |  |--g
        /|\          |  +--h
      / / \ \        |--c
     b  c d  e       |--d
    /|\     /|\      +--e
   f g h   i j k        |--i
            / \         |--j
            l m         |  |--l
             / \        |  +--m
             n o        |     |--n
                        |     +--o
                        +--k
    \endcode
*/
void make_a_o(TL::Tree<char> & T) {
    TL::Tree<char> Th;
    T.Erase();
    T = 'a'; // inserta la raiz 'A'

    /***********************************/

    T.Change_Child(0, 'b'); //     a
    T.Change_Child(1, 'c'); //   ./|\.
    T.Change_Child(2, 'd'); // ./ / \ \.
    T.Change_Child(3, 'e'); // b  c d  e

    /***********************************/

    Th = T.Child(0); // 'b'

    Th.Change_Child(0, 'f'); //   b
    Th.Change_Child(1, 'g'); // ./|\.
    Th.Change_Child(2, 'h'); // f g h

    /***********************************/

    Th = T.Child(3);  //  'e'
    Th.Change_Child(0, 'i'); //   e
    Th.Change_Child(1, 'j'); // ./|\.
    Th.Change_Child(2, 'k'); // i j k

    /***********************************/

    Th = Th.Child(1);      //  'j'
    Th.Change_Child(0, 'l'); // ./ \.
    Th.Change_Child(1, 'm'); //  l m

    Th = Th.Child(1);      //  'm'
    Th.Change_Child(0, 'n'); // ./ \.
    Th.Change_Child(1, 'o'); //  n o
}

/** <code>T = ( 0 ( 1 ( 3 4 ) 2 ( 5 6 ) ) )</code>.
    \code
                T = 0
     T = 0          |--1
       ./ \.        |  |--3
       1   2        |  +--4
     ./ \ / \.      +--2
      3 4 5 6          |--5
                       +--6
    \endcode
*/
void make_0_6(TL::Tree<char> & T) {
    TL::Tree<char> Th;
    T.Erase();
    T = '0'; // inserta la raiz '0'

    /***********************************/

                            //     0
    T.Change_Child(0, '1'); //   ./ \.
    T.Change_Child(1, '2'); //   1   2

    /***********************************/

    Th = T.Child(0);          // '1'
    Th.Change_Child(0, '3'); // ./ \.
    Th.Change_Child(1, '4'); // 3   4

    /***********************************/

    Th = T.Child(1);          // '2'
    Th.Change_Child(0, '5'); // ./ \.
    Th.Change_Child(1, '6'); // 5   6
}

/** <code>T = ( F ( B ( A ( C E ) D ) ) G ( I ( H ) ) )</code>.
    \code
                 F
      T = F      |--B
        ./ \.    |  |--A
        B   G    |  |  |--C
      ./ \   \.  |  |  +--E
      A   D   I  |  +--D
    ./ \     /.  +--G
    C   E   H       +--I
    \endcode           +--H
*/
void make_A_H(TL::Tree<char> & T) {
    TL::Tree<char> A, B, G, I;
    T.Erase();

    /***********************************/
    A = 'A';                //     A
    A.Change_Child(0, 'C'); //   ./ \.
    A.Change_Child(1, 'E'); //   C   E

    /***********************************/
    I = 'I';                //     I
    I.Change_Child(0, 'H'); //   ./.
                            //   H

    /***********************************/
    B = 'B';                //     B
    B.Graft(0, A);          //   ./ \.
    B.Change_Child(1, 'D'); //   A   D

    /***********************************/
    G = 'G';                //     G
                            //      \.
    G.Graft(1, I);          //       I

    /***********************************/
    T = 'F';                //     F
    T.Graft(0, B);          //   ./ \.
    T.Graft(1, G);          //   B   G
}

/** <code>T = ( A ( B ( D ( H I) E ( J K ) ) C ( F ( L M ) G ( N O ) ) ) )</code>.
    \code
                  T = A
                      |--B
                      |  |--D
       T = A          |  |  |--H
         ./ \.        |  |  +--I
        ./   \.       |  +--E
       ./     \.      |     |--J
       B       C      |     +--K
     ./ \     / \.    +--C
     D   E   F   G       |--F
   ./ \ / \ / \ / \.     |  |--L
    H I J K L M N O      |  +--M
    \endcode             +--G
                            |--N
                            +--O
*/
void make_A_O(TL::Tree<char> & T) {
    TL::Tree<char> B, D, E, C, F, G;
    T.Erase();

    /***********************************/
    D = 'D';                //     D
    D.Change_Child(0, 'H'); //   ./ \.
    D.Change_Child(1, 'I'); //   H   I

    /***********************************/
    E = 'E';                //     E
    E.Change_Child(0, 'J'); //   ./ \.
    E.Change_Child(1, 'K'); //   J   K

    /***********************************/
    F = 'F';                //     F
    F.Change_Child(0, 'L'); //   ./ \.
    F.Change_Child(1, 'M'); //   L   M

    /***********************************/
    G = 'G';                //     G
    G.Change_Child(0, 'N'); //   ./ \.
    G.Change_Child(1, 'O'); //   N   O

    /***********************************/
    B = 'B';                //     B
    B.Graft(0, D);          //   ./ \.
    B.Graft(1, E);          //   N   O

    /***********************************/
    C = 'C';                //     B
    C.Graft(0, F);          //   ./ \.
    C.Graft(1, G);          //   F   G

    /***********************************/
    T = 'A';                //     A
    T.Graft(0, B);          //   ./ \.
    T.Graft(1, C);          //   B   C
}

#include <cmath> // rand() && srand()

#ifdef English_dox
/// C++ encapsulation of a generator as a Java iterator.
#endif
#ifdef Spanish_dox
/// Encapsulamiento C++ de un generador como una iteración Java.
#endif
class Random {
     unsigned m_qty;   ///< #.
     unsigned m_last;  ///< Max.
     long     m_val;   ///< current().
public:
     /// \c Iterator::init()
     Random( unsigned n=1 , long seed=3145159 )
     :   m_qty(0), m_last(n) { srand(seed); }

     /// \c Iterator::hastNext()
     bool hasNext() const { return m_qty < m_last; }
     /// \c Iterator::next()
     const long& next()
     { m_qty++; return (m_val = rand()) ; }
};

#include <iostream>

#ifdef English_dox
/// Example usage of Java iterators as generators.
#endif
#ifdef Spanish_dox
/// Ejemplo de uso de iteraciones Java como generadores.
#endif
void generateRandom( ) {
    Random iter( 15, 271828 );
    while ( iter.hasNext()  ) {
        std::cout << iter.next() << std::endl;
    }
}

#ifdef English_dox
/// Example usage of the \c iterJava<> iterator class.
#endif
#ifdef Spanish_dox
/// Ejemplo de uso de la clase de iteración \c iterJava<>.
#endif
template <class Collection>
void useIterator( Collection& C ) {
//  iterJava< typename Collection::iterator > iter( C.begin(), C.end() );
    typedef iterJava< typename Collection::iterator > ITER;
    ITER iter( C.begin(), C.end() );
    while ( iter.hasNext() ) {
        std::cout << iter.next();
        C.erase( iter ); // C.erase( iter.current() );
    }
}

#undef ZTREE
#ifdef ZTREE
    using namespace TL;  // avoid errors within Tree_Ex.h
    #include "Tree_Ex.h"
#endif

/// Test ==> \c main() ==>  \c iterJava().
int main() {
    test_iterJava tester;
    tester.setUp();
    tester.run();
    std::cout << tester.report();

    if (false) {
        std::list<long> L = makeList_long( "( 1 2 3 4 5 )" );
        std::cout << "useIterator( L ); ==> ";
        useIterator( L );
        assert( L.empty() );
    }
    if (false) {
        generateRandom( );
    }
    #ifdef ZTREE
        TL::Tree<char> ZT;
        make_A_O( ZT );
        Ztree_Print( ZT );
    #endif
}
// EOF: test_iterJava.cpp