// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_H_
#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_H_


#include <sstream>
#include <string>
#include <cstdlib>
#include <ctime>

#include <dlib/memory_manager_global.h>
#include <dlib/memory_manager_stateless.h>
#include <dlib/binary_search_tree.h>
#include "tester.h"

namespace  
{

    using namespace test;
    using namespace dlib;

    logger dlog("test.binary_search_tree");

    template <
        typename bst
        >
    void binary_search_tree_kernel_test (
    )
    /*!
        requires
            - bst is an implementation of 
              binary_search_tree/binary_search_tree_kernel_abstract.h is instantiated 
              to map int to int
        ensures
            - runs tests on bst for compliance with the specs 
    !*/
    {        

        bst test, test2;

        srand(static_cast<unsigned int>(time(0)));


        DLIB_TEST(test.count(3) == 0);

        enumerable<map_pair<int,int> >& e = test;
        DLIB_TEST(e.at_start() == true);

        DLIB_TEST(test.count(3) == 0);

        for (int i = 0; i < 4; ++i)
        {
            DLIB_TEST(test.size() == 0);
            DLIB_TEST(test.count(3) == 0);
            DLIB_TEST(test.height() == 0);
            DLIB_TEST(test[5] == 0);
            DLIB_TEST(test[0] == 0);
            DLIB_TEST(test.at_start());
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.count(3) == 0);

            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.count(3) == 0);

            DLIB_TEST(test.at_start() == false);
            DLIB_TEST(test.current_element_valid() == false);

            test.clear();
            test.position_enumerator(5);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.at_start() == false);
            test.position_enumerator(5);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.at_start() == false);
            test.position_enumerator(9);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.at_start() == false);
            test.clear();
            test.position_enumerator(5);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.at_start() == false);
            test.position_enumerator(5);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.at_start() == false);
            test.position_enumerator(9);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.at_start() == false);
            test.clear();
            DLIB_TEST(test.at_start() == true);
            DLIB_TEST(test.current_element_valid() == false);


            DLIB_TEST(test.count(3) == 0);

            DLIB_TEST(test.size() == 0);
            DLIB_TEST(test.height() == 0);
            DLIB_TEST(test[5] == 0);
            DLIB_TEST(test[0] == 0);
            DLIB_TEST(const_cast<const bst&>(test)[5] == 0);
            DLIB_TEST(const_cast<const bst&>(test)[0] == 0);
            DLIB_TEST(test.at_start());
            DLIB_TEST(test.current_element_valid() == false);

            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);

            DLIB_TEST(test.at_start() == false);
            DLIB_TEST(test.current_element_valid() == false);


            DLIB_TEST(test.count(3) == 0);
            test.reset();
            DLIB_TEST(test.count(3) == 0);

            DLIB_TEST(test.at_start());
            DLIB_TEST(test.current_element_valid() == false);






            int a = 0, b = 0;

            for (int i = 0; i < 10000; ++i)
            {
                a = ::rand()%1000;
                int temp = a;
                unsigned long count = test.count(a);
                test.add(a,b);
                DLIB_TEST(test.count(temp) == count+1);
            }


            {
                unsigned long count = test.count(3);

                a = 3; test.add(a,b); ++count;
                DLIB_TEST(test.count(3) == count);
                a = 3; test.add(a,b); ++count;
                DLIB_TEST(test.count(3) == count);
                a = 3; test.add(a,b); ++count;
                DLIB_TEST(test.count(3) == count);
                a = 3; test.add(a,b); ++count;
                DLIB_TEST(test.count(3) == count);
            }


            test.clear();





            for (int i = 0; i < 10000; ++i)
            {
                a = ::rand()&0x7FFF;
                b = 0;
                int temp = a;
                unsigned long count = test.count(a);
                test.add(a,b);
                DLIB_TEST(test.count(temp) == count+1);
            }

            // serialize the state of test, then clear test, then
            // load the state back into test.
            std::ostringstream sout;
            serialize(test,sout);
            std::istringstream sin(sout.str());
            test.clear();
            deserialize(test,sin);

            DLIB_TEST(test.size() == 10000);
            DLIB_TEST(test.at_start() == true);
            DLIB_TEST(test.current_element_valid() == false);


            DLIB_TEST_MSG(test.height() > 13 && test.height() <= 26,"this is somewhat of an implementation dependent "
                         << "but really it should be in this range or the implementation is just crap");

            a = 0;
            unsigned long count = 0;
            while (test.move_next())
            {
                DLIB_TEST_MSG(a <= test.element().key(),"the numers are out of order but they should be in order");
                a = test.element().key();
                ++count;


                DLIB_TEST(test.at_start() == false);
                DLIB_TEST(test.current_element_valid() == true);
            }

            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.move_next() == false);

            DLIB_TEST(count == 10000);




            DLIB_TEST_MSG(test.height() > 13 && test.height() <= 26,"this is somewhat of an implementation dependent "
                         << "but really it should be in this range or the implementation is just crap");

            DLIB_TEST(test.at_start() == false);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.size() == 10000);


            swap(test,test2);


            test2.reset();
            count = 0;
            a = 0;
            while (test2.move_next())
            {
                DLIB_TEST_MSG(a <= test2.element().key(),"the numers are out of order but they should be in order");
                a = test2.element().key();
                ++count;


                DLIB_TEST(test2.at_start() == false);
                DLIB_TEST(test2.current_element_valid() == true);

                if (count == 5000)
                {
                    break;
                }
            }

            DLIB_TEST(test2.move_next() == true);
            DLIB_TEST(test2.move_next() == true);
            DLIB_TEST(test2.move_next() == true);


            test2.reset();

            count = 0;
            a = 0;
            while (test2.move_next())
            {
                DLIB_TEST_MSG(a <= test2.element().key(),"the numers are out of order but they should be in order");
                a = test2.element().key();
                ++count;


                DLIB_TEST(test2.at_start() == false);
                DLIB_TEST(test2.current_element_valid() == true);
            }

            DLIB_TEST(count == 10000);
            DLIB_TEST(test2.move_next() == false);
            DLIB_TEST(test2.move_next() == false);
            DLIB_TEST(test2.move_next() == false);








            int last = 0;
            asc_pair_remover<int,int,typename bst::compare_type>& asdf = test2;
            DLIB_TEST(asdf.size() > 0);
            while (asdf.size() > 0)
            {
                asdf.remove_any(a,b);
                DLIB_TEST(last <= a);
                last = a;
                --count;
                DLIB_TEST(asdf.size() == count);
            }


            DLIB_TEST(test2.size() == 0);
            DLIB_TEST(test2.height() ==0);
            DLIB_TEST(test2.at_start() == true);
            DLIB_TEST(test2.current_element_valid() == false);
            DLIB_TEST(test2.move_next() == false);
            DLIB_TEST(test2.move_next() == false);
            DLIB_TEST(test2.move_next() == false);




            for (int i = 0; i < 10000; ++i)
            {
                a = i;
                b = i;
                test2.add(a,b);
                DLIB_TEST(test2.size() == (unsigned int)(i +1));
                DLIB_TEST(test2.count(i) == 1);
            }

            a = 0;
            test2.position_enumerator(a);
            DLIB_TEST(test2.at_start() == false);
            DLIB_TEST(test2.element().key() == a);
            DLIB_TEST(test2.element().value() == a);
            a = 0;
            test2.position_enumerator(a);
            DLIB_TEST(test2.element().key() == a);
            DLIB_TEST(test2.element().value() == a);
            a = 8;
            test2.position_enumerator(a);
            DLIB_TEST(test2.at_start() == false);
            DLIB_TEST(test2.element().key() == a);
            DLIB_TEST(test2.element().value() == a);
            a = 1;
            test2.position_enumerator(a);
            DLIB_TEST(test2.element().key() == a);
            DLIB_TEST(test2.element().value() == a);
            a = -29;
            test2.position_enumerator(a);
            DLIB_TEST(test2.element().key() == 0);
            DLIB_TEST(test2.element().value() == 0);
            a = 10000;
            test2.position_enumerator(a);
            DLIB_TEST(test2.at_start() == false);
            DLIB_TEST(test2.current_element_valid() == false);
            a = -29;
            test2.position_enumerator(a);
            DLIB_TEST(test2.element().key() == 0);
            DLIB_TEST(test2.element().value() == 0);
            a = 8;
            test2.position_enumerator(a);
            DLIB_TEST(test2.at_start() == false);
            DLIB_TEST(test2.element().key() == a);
            DLIB_TEST(test2.element().value() == a);
            test2.reset();


            DLIB_TEST_MSG(test2.height() > 13 && test2.height() <= 26,"this is somewhat of an implementation dependent "
                         << "but really it should be in this range or the implementation is just crap");

            DLIB_TEST(test2.at_start() == true);
            DLIB_TEST(test2.current_element_valid() == false);
            DLIB_TEST(test2.size() == 10000);


            for (int i = 0; i < 10000; ++i)
            {
                DLIB_TEST(test2.move_next() == true);
                DLIB_TEST(test2.element().key() == i);
            }



            DLIB_TEST_MSG(test2.height() > 13 && test2.height() <= 26,"this is somewhat of an implementation dependent "
                         << "but really it should be in this range or the implementation is just crap");

            DLIB_TEST(test2.at_start() == false);
            DLIB_TEST(test2.current_element_valid() == true);
            DLIB_TEST(test2.size() == 10000);


            DLIB_TEST(test2.move_next() == false);
            DLIB_TEST(test2.current_element_valid() == false);

            a = 3;
            test2.add(a,b);
            DLIB_TEST(test2.count(3) == 2);


            for (int i = 0; i < 10000; ++i)
            {
                test2.remove(i,a,b);
                DLIB_TEST(i == a);
            }
            test2.remove(3,a,b);


            DLIB_TEST(test2.size() == 0);
            DLIB_TEST(test2.height() == 0);
            DLIB_TEST(test2.at_start() == true);
            DLIB_TEST(test2.current_element_valid() == false);
            DLIB_TEST(test2.move_next() == false);
            DLIB_TEST(test2.at_start() == false);
            DLIB_TEST(test2.current_element_valid() == false);



            test2.clear();


            int m = 0;
            for (int i = 0; i < 10000; ++i)
            {
                a = ::rand()&0x7FFF;
                m = std::max(a,m);
                test2.add(a,b);
            }

            DLIB_TEST(test2.at_start() == true);
            DLIB_TEST(test2.move_next() == true);
            DLIB_TEST(test2.at_start() == false);
            DLIB_TEST(test2.current_element_valid() == true);
            DLIB_TEST(test2.move_next() == true);
            DLIB_TEST(test2.current_element_valid() == true);
            DLIB_TEST(test2.move_next() == true);
            DLIB_TEST(test2.current_element_valid() == true);
            DLIB_TEST(test2.move_next() == true);
            DLIB_TEST(test2.current_element_valid() == true);
            DLIB_TEST(test2.at_start() == false);

            for (int i = 0; i < 10000; ++i)
            {
                a = ::rand()&0xFFFF;
                test2.position_enumerator(a);
                if (test2[a])
                {
                    DLIB_TEST(test2.element().key() == a);
                }
                else if (a <= m)
                {
                    DLIB_TEST(test2.element().key() > a);
                }
            }

            test2.clear();

            DLIB_TEST(test2.current_element_valid() == false);
            DLIB_TEST(test2.at_start() == true);
            DLIB_TEST(test2.move_next() == false);
            DLIB_TEST(test2.at_start() == false);
            DLIB_TEST(test2.current_element_valid() == false);
            DLIB_TEST(test2.move_next() == false);
            DLIB_TEST(test2.current_element_valid() == false);
            DLIB_TEST(test2.move_next() == false);
            DLIB_TEST(test2.current_element_valid() == false);
            DLIB_TEST(test2.at_start() == false);


            DLIB_TEST(test2.size() == 0);
            DLIB_TEST(test2.height() == 0);


            for (int i = 0; i < 20000; ++i)
            {
                a = ::rand()&0x7FFF;
                b = a;
                test2.add(a,b);
            }


            DLIB_TEST(test2.size() == 20000);



            // remove a bunch of elements randomly
            int c;
            for (int i = 0; i < 50000; ++i)
            {
                a = ::rand()&0x7FFF;
                if (test2[a] != 0)
                {
                    test2.remove(a,b,c);
                    DLIB_TEST(a == b);
                }
            }


            // now add a bunch more
            for (int i = 0; i < 10000; ++i)
            {
                a = ::rand()&0x7FFF;
                b = a;
                test2.add(a,b);
            }


            // now iterate over it all and then remove all elements
            {
                int* array = new int[test2.size()];
                int* tmp = array;
                DLIB_TEST(test2.at_start() == true);
                while (test2.move_next())
                {
                    *tmp = test2.element().key();
                    ++tmp;
                }

                DLIB_TEST(test2.at_start() == false);
                DLIB_TEST(test2.current_element_valid() == false);
                DLIB_TEST(test2.move_next() == false);

                tmp = array;
                for (int i = 0; i < 10000; ++i)
                {
                    DLIB_TEST(*test2[*tmp] == *tmp);
                    DLIB_TEST(*test2[*tmp] == *tmp);
                    DLIB_TEST(*test2[*tmp] == *tmp);
                    DLIB_TEST(*const_cast<const bst&>(test2)[*tmp] == *tmp);
                    ++tmp;
                }

                tmp = array;
                while (test2.size() > 0)
                {
                    unsigned long count = test2.count(*tmp);
                    test2.destroy(*tmp);
                    DLIB_TEST(test2.count(*tmp)+1 == count);
                    ++tmp;
                }

                DLIB_TEST(test2.at_start() == true);
                DLIB_TEST(test2.current_element_valid() == false);
                DLIB_TEST(test2.move_next() == false);
                DLIB_TEST(test2.at_start() == false);
                test.swap(test2);
                test.reset();

                delete [] array;
            }


            DLIB_TEST(test.size() == 0);
            DLIB_TEST(test.height() == 0);

            for (unsigned long i = 1; i < 100; ++i)
            {
                a = 1234;
                test.add(a,b);
                DLIB_TEST(test.count(1234) == i);
            }

            test.clear();






            for (int m = 0; m < 3; ++m)
            {

                test2.clear();

                DLIB_TEST(test2.current_element_valid() == false);
                DLIB_TEST(test2.at_start() == true);
                DLIB_TEST(test2.move_next() == false);
                DLIB_TEST(test2.at_start() == false);
                DLIB_TEST(test2.current_element_valid() == false);
                DLIB_TEST(test2.move_next() == false);
                DLIB_TEST(test2.current_element_valid() == false);
                DLIB_TEST(test2.move_next() == false);
                DLIB_TEST(test2.current_element_valid() == false);
                DLIB_TEST(test2.at_start() == false);


                DLIB_TEST(test2.size() == 0);
                DLIB_TEST(test2.height() == 0);


                int counter = 0;
                while (counter < 10000)
                {
                    a = ::rand()&0x7FFF;
                    b = ::rand()&0x7FFF;
                    if (test2[a] == 0)
                    {
                        test2.add(a,b);
                        ++counter;
                    }

                }



                DLIB_TEST(test2.size() == 10000);



                // remove a bunch of elements randomly                
                for (int i = 0; i < 20000; ++i)
                {
                    a = ::rand()&0x7FFF;
                    if (test2[a] != 0)
                    {
                        test2.remove(a,b,c);
                        DLIB_TEST(a == b);
                    }
                }


                // now add a bunch more
                for (int i = 0; i < 20000; ++i)
                {
                    a = ::rand()&0x7FFF;
                    b = ::rand()&0x7FFF;
                    if (test2[a] == 0)
                        test2.add(a,b);
                }


                // now iterate over it all and then remove all elements
                {
                    int* array = new int[test2.size()];
                    int* array_val = new int[test2.size()];
                    int* tmp = array;
                    int* tmp_val = array_val;
                    DLIB_TEST(test2.at_start() == true);
                    int count = 0;
                    while (test2.move_next())
                    {
                        *tmp = test2.element().key();
                        ++tmp;
                        *tmp_val = test2.element().value();
                        ++tmp_val;

                        DLIB_TEST(*test2[*(tmp-1)] == *(tmp_val-1));
                        ++count;
                    }

                    DLIB_TEST(count == (int)test2.size());
                    DLIB_TEST(test2.at_start() == false);
                    DLIB_TEST(test2.current_element_valid() == false);
                    DLIB_TEST(test2.move_next() == false);

                    tmp = array;
                    tmp_val = array_val;
                    for (unsigned long i = 0; i < test2.size(); ++i)
                    {
                        DLIB_TEST_MSG(*test2[*tmp] == *tmp_val,i);
                        DLIB_TEST(*test2[*tmp] == *tmp_val);
                        DLIB_TEST(*test2[*tmp] == *tmp_val);
                        DLIB_TEST(*const_cast<const bst&>(test2)[*tmp] == *tmp_val);
                        ++tmp;
                        ++tmp_val;
                    }

                    //  out << "\nsize:   " << test2.size() << endl;
                    //  out << "height: " << test2.height() << endl;

                    tmp = array;
                    while (test2.size() > 0)
                    {
                        unsigned long count = test2.count(*tmp);
                        test2.destroy(*tmp);
                        DLIB_TEST(test2.count(*tmp)+1 == count);
                        ++tmp;
                    }

                    DLIB_TEST(test2.at_start() == true);
                    DLIB_TEST(test2.current_element_valid() == false);
                    DLIB_TEST(test2.move_next() == false);
                    DLIB_TEST(test2.at_start() == false);
                    test.swap(test2);
                    test.reset();

                    delete [] array;
                    delete [] array_val;
                }


                DLIB_TEST(test.size() == 0);
                DLIB_TEST(test.height() == 0);

                for (unsigned long i = 1; i < 100; ++i)
                {
                    a = 1234;
                    test.add(a,b);
                    DLIB_TEST(test.count(1234) == i);
                }

                test.clear();

            }



            a = 1;
            b = 2;

            test.add(a,b);

            test.position_enumerator(0);
            a = 0;
            b = 0;
            DLIB_TEST(test.height() == 1);
            test.remove_current_element(a,b);
            DLIB_TEST(a == 1);
            DLIB_TEST(b == 2);
            DLIB_TEST(test.at_start() == false);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.height() == 0);
            DLIB_TEST(test.size() == 0);


            a = 1;
            b = 2;
            test.add(a,b);
            a = 1;
            b = 2;
            test.add(a,b);

            test.position_enumerator(0);
            a = 0;
            b = 0;
            DLIB_TEST(test.height() == 2);
            test.remove_current_element(a,b);
            DLIB_TEST(a == 1);
            DLIB_TEST(b == 2);
            DLIB_TEST(test.at_start() == false);
            DLIB_TEST(test.current_element_valid() == true);
            DLIB_TEST(test.height() == 1);
            DLIB_TEST(test.size() == 1);

            test.remove_current_element(a,b);
            DLIB_TEST(a == 1);
            DLIB_TEST(b == 2);
            DLIB_TEST(test.at_start() == false);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.height() == 0);
            DLIB_TEST(test.size() == 0);

            for (int i = 0; i < 100; ++i)
            {
                a = i;
                b = i;
                test.add(a,b);
            }

            DLIB_TEST(test.size() == 100);
            test.remove_last_in_order(a,b);
            DLIB_TEST(a == 99);
            DLIB_TEST(b == 99);
            DLIB_TEST(test.size() == 99);
            test.remove_last_in_order(a,b);
            DLIB_TEST(a == 98);
            DLIB_TEST(b == 98);
            DLIB_TEST(test.size() == 98);

            test.position_enumerator(-10);
            for (int i = 0; i < 97; ++i)
            {
                DLIB_TEST(test.element().key() == i);
                DLIB_TEST(test.element().value() == i);
                DLIB_TEST(test.move_next());
            }
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.current_element_valid() == false);


            test.position_enumerator(10);
            for (int i = 10; i < 97; ++i)
            {
                DLIB_TEST(test.element().key() == i);
                DLIB_TEST(test.element().value() == i);
                DLIB_TEST(test.move_next());
            }
            DLIB_TEST(test.move_next() == false);
            DLIB_TEST(test.current_element_valid() == false);

            test.reset();
            DLIB_TEST(test.at_start());
            DLIB_TEST(test.current_element_valid() == false);
            for (int i = 0; i < 98; ++i)
            {
                DLIB_TEST(test.move_next());
                DLIB_TEST(test.element().key() == i);
                DLIB_TEST(test.element().value() == i);
            }
            DLIB_TEST_MSG(test.size() == 98, test.size());
            DLIB_TEST(test.move_next() == false);

            test.position_enumerator(98);
            DLIB_TEST(test.current_element_valid() == false);
            DLIB_TEST(test.at_start() == false);


            test.position_enumerator(50);
            DLIB_TEST(test.element().key() == 50);
            DLIB_TEST(test.element().value() == 50);
            DLIB_TEST(test[50] != 0);
            test.remove_current_element(a,b);
            DLIB_TEST(test[50] == 0);
            DLIB_TEST_MSG(test.size() == 97, test.size());
            DLIB_TEST(a == 50);
            DLIB_TEST(b == 50);
            DLIB_TEST(test.element().key() == 51);
            DLIB_TEST(test.element().value() == 51);
            DLIB_TEST(test.current_element_valid());
            test.remove_current_element(a,b);
            DLIB_TEST_MSG(test.size() == 96, test.size());
            DLIB_TEST(a == 51);
            DLIB_TEST(b == 51);
            DLIB_TEST_MSG(test.element().key() == 52,test.element().key());
            DLIB_TEST_MSG(test.element().value() == 52,test.element().value());
            DLIB_TEST(test.current_element_valid());
            test.remove_current_element(a,b);
            DLIB_TEST_MSG(test.size() == 95, test.size());
            DLIB_TEST(a == 52);
            DLIB_TEST(b == 52);
            DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
            DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
            DLIB_TEST(test.current_element_valid());
            test.position_enumerator(50);
            DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
            DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
            DLIB_TEST(test.current_element_valid());
            test.position_enumerator(51);
            DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
            DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
            DLIB_TEST(test.current_element_valid());
            test.position_enumerator(52);
            DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
            DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
            DLIB_TEST(test.current_element_valid());
            test.position_enumerator(53);
            DLIB_TEST_MSG(test.element().key() == 53,test.element().key());
            DLIB_TEST_MSG(test.element().value() == 53,test.element().value());
            DLIB_TEST(test.current_element_valid());

            test.reset();
            test.move_next();
            int lasta = -1, lastb = -1;
            count = 0;
            while (test.current_element_valid() )
            {
                ++count;
                int c = test.element().key();
                int d = test.element().value();
                test.remove_current_element(a,b);
                DLIB_TEST(c == a);
                DLIB_TEST(d == a);
                DLIB_TEST(lasta < a);
                DLIB_TEST(lastb < b);
                lasta = a;
                lastb = b;
            }
            DLIB_TEST_MSG(count == 95, count);
            DLIB_TEST(test.size() == 0);
            DLIB_TEST(test.height() == 0);

            test.clear();

            for (int i = 0; i < 1000; ++i)
            {
                a = 1;
                b = 1;
                test.add(a,b);
            }

            for (int i = 0; i < 40; ++i)
            {
                int num = ::rand()%800 + 1;
                test.reset();
                for (int j = 0; j < num; ++j)
                {
                    DLIB_TEST(test.move_next());
                }					             
                DLIB_TEST_MSG(test.current_element_valid(),"size: " << test.size() << "   num: " << num);
                test.remove_current_element(a,b);
                DLIB_TEST_MSG(test.current_element_valid(),"size: " << test.size() << "   num: " << num);
                test.remove_current_element(a,b);
                test.position_enumerator(1);
                if (test.current_element_valid())
                    test.remove_current_element(a,b);
                DLIB_TEST(a == 1);
                DLIB_TEST(b == 1);
            }

            test.clear();

        }


        test.clear();
        test2.clear();

    }

}

#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_H_

