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

    #include <dlib/any.h>
    #include <sstream>
    #include <string>
    #include <cstdlib>
    #include <ctime>
    #include <vector>
    #include "../rand.h"

    #include "tester.h"

    namespace
    {

        using namespace test;
        using namespace dlib;
        using namespace std;

        logger dlog("test.any_function");

    // ----------------------------------------------------------------------------------------

        int add ( int a, int b) { return a + b; }
        string cat ( string a, string b) { return a + b; }

    // ----------------------------------------------------------------------------------------

        void set_vals1( int& a) { a = 1; }
        void set_vals2( int& a, int& b) { a = 1; b = 2; }
        void set_vals3( int& a, int& b, int& c) { a = 1; b = 2; c = 3; }
        void set_vals4( int& a, int& b, int& c, int& d) { a = 1; b = 2; c = 3; d = 4; }
        void set_vals5( int& a, int& b, int& c, int& d, int& e) { a = 1; b = 2; c = 3; d = 4; e = 5; }
        void set_vals6( int& a, int& b, int& c, int& d, int& e, int& f) { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; }
        void set_vals7( int& a, int& b, int& c, int& d, int& e, int& f, int& g) { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; }

        void set_vals8( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h)
        { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; }

        void set_vals9( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h, int& i)
        { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; i = 9;}

        void set_vals10( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h, int& i, int& j)
        { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; i = 9; j = 10;}

        void zero_vals( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h, int& i, int& j)
        { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; g = 0; h = 0; i = 0; j = 0;}

    // ----------------------------------------------------------------------------------------

        struct test
        {
            int operator()() const { return 4; }
        };

        struct test2
        {
            int v;

            test2() : v(0) {}
            test2(int val) : v(val) {}
            int operator()() const { return v; }
        };

    // ----------------------------------------------------------------------------------------

        void test_contains_4(
            const any_function<int()> a
        )
        {
            DLIB_TEST(a.is_empty() == false);
            DLIB_TEST(a.is_set() == true);
            DLIB_TEST(a.contains<test>() == true);
            DLIB_TEST(a.contains<int(*)()>() == false);
            DLIB_TEST(any_cast<test>(a)() == 4);
            DLIB_TEST(a() == 4);
        }

    // ----------------------------------------------------------------------------------------

        void run_test()
        {
            any_function<int()> a, b, c;

            DLIB_TEST(a.is_empty());
            DLIB_TEST(a.is_set()==false);
            DLIB_TEST(a.contains<int(*)()>() == false);
            DLIB_TEST(a.contains<test>() == false);
            DLIB_TEST(a.is_empty());

            a = b;

            swap(a,b);
            a.swap(b);

            a = test();
            test_contains_4(a);

            bool error = false;
            try
            {
                any_cast<int(*)()>(a);
            }
            catch (bad_any_cast&)
            {
                error = true;
            }
            DLIB_TEST(error);

            swap(a,b);

            test_contains_4(b);

            DLIB_TEST(a.is_empty());

            a = b;

            test_contains_4(a);

            c.get<test2>() = test2(10);
            DLIB_TEST(c.get<test2>().v == 10);

            a = c;
            DLIB_TEST(a.cast_to<test2>().v == 10);

            a.clear();
            DLIB_TEST(a.is_empty());
            error = false;
            try
            {
                any_cast<test>(a);
            }
            catch (bad_any_cast&)
            {
                error = true;
            }
            DLIB_TEST(error);

        }

    // ----------------------------------------------------------------------------------------

        void run_test2()
        {
            any_function<int(int,int)> f = &add;

            DLIB_TEST(f(1,3) == 4);

            any_function<string(string,string)> g(&cat);
            DLIB_TEST(g("one", "two") == "onetwo");
        }

    // ----------------------------------------------------------------------------------------

        void run_test3()
        {
            any_function<void(int&)> f1;
            any_function<void(int&,int&)> f2;
            any_function<void(int&,int&,int&)> f3;
            any_function<void(int&,int&,int&,int&)> f4;
            any_function<void(int&,int&,int&,int&,int&)> f5;
            any_function<void(int&,int&,int&,int&,int&,int&)> f6;
            any_function<void(int&,int&,int&,int&,int&,int&,int&)> f7;
            any_function<void(int&,int&,int&,int&,int&,int&,int&,int&)> f8;
            any_function<void(int&,int&,int&,int&,int&,int&,int&,int&,int&)> f9;
            any_function<void(int&,int&,int&,int&,int&,int&,int&,int&,int&,int&)> f10;

            f1 = set_vals1;
            f2 = set_vals2;
            f3 = set_vals3;
            f4 = set_vals4;
            f5 = set_vals5;
            f6 = set_vals6;
            f7 = set_vals7;
            f8 = set_vals8;
            f9 = set_vals9;
            f10 = set_vals10;

            int a,b,c,d,e,f,g,h,i,j;

            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f1(a);
            DLIB_TEST(a==1);
            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f2(a,b);
            DLIB_TEST(a==1 && b==2);
            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f3(a,b,c);
            DLIB_TEST(a==1 && b==2 && c==3);
            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f4(a,b,c,d);
            DLIB_TEST(a==1 && b==2 && c==3 && d==4);
            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f5(a,b,c,d,e);
            DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5);
            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f6(a,b,c,d,e,f);
            DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6);
            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f7(a,b,c,d,e,f,g);
            DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7);
            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f8(a,b,c,d,e,f,g,h);
            DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7 && h==8);
            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f9(a,b,c,d,e,f,g,h,i);
            DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7 && h==8 && i==9);
            zero_vals(a,b,c,d,e,f,g,h,i,j);

            f10(a,b,c,d,e,f,g,h,i,j);
            DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7 && h==8 && i==9 && j==10);
            zero_vals(a,b,c,d,e,f,g,h,i,j);
        }
    // ----------------------------------------------------------------------------------------

        class test_any_function : public tester
        {
        public:
            test_any_function (
            ) :
                tester ("test_any_function",
                        "Runs tests on the any_function component.")
            {}

            void perform_test (
            )
            {
                print_spinner();
                run_test();
                print_spinner();
                run_test2();
                print_spinner();
                run_test3();
            }
        } a;

    }