/**************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/




// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"
// autogenerated file with codegen.pl

#include <algorithm> // STL

#include "gtest/gtest.h"
#include <rtl/random.h>

namespace rtl_random
{

class createPool : public ::testing::Test
{
public:
    // initialise your test code values here.
    void SetUp()
    {
    }

    void TearDown()
    {
    }
}; // class createPool

TEST_F(createPool, createPool_001)
{
    // this is demonstration code

    rtlRandomPool aPool = rtl_random_createPool();

    // LLA: seems to be that an other test is not possible for createPool()
    ASSERT_TRUE(aPool != NULL) << "create failed";
    rtl_random_destroyPool(aPool);
}

class destroyPool : public ::testing::Test
{
public:
    // initialise your test code values here.
    void SetUp()
    {
    }

    void TearDown()
    {
    }
}; // class destroyPool

TEST_F(destroyPool, destroyPool_000)
{
    // GPF, if failed
    rtl_random_destroyPool(NULL);
}

TEST_F(destroyPool, destroyPool_001)
{
    rtlRandomPool aPool = rtl_random_createPool();

    // LLA: seems to be that an other test is not possible for createPool()
    ASSERT_TRUE(aPool != NULL) << "create failed";

    rtl_random_destroyPool(aPool);
}

class addBytes : public ::testing::Test
{
public:
    // initialise your test code values here.
    void SetUp()
    {
    }

    void TearDown()
    {
    }
}; // class addBytes

TEST_F(addBytes, addBytes_000)
{
    rtlRandomPool aPool = rtl_random_createPool();

    sal_uInt32  nBufLen = 4;
    sal_uInt8   *pBuffer = new sal_uInt8[ nBufLen ];
    memset(pBuffer, 0, nBufLen);

    rtlRandomError aError = rtl_random_addBytes(NULL, NULL, 0);
    ASSERT_TRUE(aError == rtl_Random_E_Argument) << "wrong parameter";

    /* rtlRandomError */ aError = rtl_random_addBytes(aPool, NULL, 0);
    ASSERT_TRUE(aError == rtl_Random_E_Argument) << "wrong parameter";

    /* rtlRandomError */ aError = rtl_random_addBytes(aPool, pBuffer, nBufLen);
    ASSERT_TRUE(aError == rtl_Random_E_None) << "wrong parameter";

    rtl_random_destroyPool(aPool);
    delete [] pBuffer;

}

TEST_F(addBytes, addBytes_001)
{
    rtlRandomPool aPool = rtl_random_createPool();

    sal_uInt32  nBufLen = 4;
    sal_uInt8   *pBuffer = new sal_uInt8[ nBufLen ];

    memset(pBuffer, 0, nBufLen);

    rtl_random_addBytes(aPool, pBuffer, nBufLen);

    printf("%2x %2x %2x %2x\n", pBuffer[0], pBuffer[1], pBuffer[2], pBuffer[3]);

    rtl_random_destroyPool(aPool);
    delete [] pBuffer;
}

class Statistics
{
protected:
    int m_nDispensation[256];

    int m_nMin;
    int m_nMax;
    int m_nAverage;
    int m_nMinDeviation;
    int m_nMaxDeviation;

public:
    void clearDispensation()
        {
            for (int i = 0;i < 256;i ++)                        // clear array
            {
                m_nDispensation[i] = 0;
            }
        }
    Statistics()
        {
            clearDispensation();
        }
    ~Statistics(){}

    void addValue(sal_Int16 _nIndex, sal_Int32 _nValue)
        {
            ASSERT_TRUE(_nIndex >= 0 && _nIndex < 256);
            m_nDispensation[_nIndex] += _nValue;
        }

    void build(sal_Int32 _nCountMax)
        {
            m_nMin = _nCountMax;
            m_nMax = 0;

            m_nAverage = _nCountMax / 256;

            m_nMinDeviation = _nCountMax;
            m_nMaxDeviation = 0;

            for (int i = 0;i < 256;i ++)                        // show dispensation
            {
                m_nMin = std::min(m_nMin, m_nDispensation[i]);
                m_nMax = std::max(m_nMax, m_nDispensation[i]);

                m_nMinDeviation = std::min(m_nMinDeviation, abs(m_nAverage - m_nDispensation[i]));
                m_nMaxDeviation = std::max(m_nMaxDeviation, abs(m_nAverage - m_nDispensation[i]));
            }
        }

    void print()
        {
            // LLA: these are only info values
            printf("\nSome statistics\n");
            printf("Min: %d\n", m_nMin);
            printf("Max: %d\n", m_nMax);
            printf("Average: %d\n", m_nAverage);
            printf("Min abs deviation: %d\n", m_nMinDeviation);
            printf("Max abs deviation: %d\n", m_nMaxDeviation);
        }

    sal_Int32 getAverage() {return m_nAverage;}
    sal_Int32 getMaxDeviation() {return m_nMaxDeviation;}

};

class getBytes : public ::testing::Test
{
public:
    // initialise your test code values here.
    void SetUp()
    {
    }

    void TearDown()
    {
    }
}; // class getBytes

TEST_F(getBytes, getBytes_000)
{
    rtlRandomPool aPool = rtl_random_createPool();

    sal_uInt32  nBufLen = 4;
    sal_uInt8   *pBuffer = new sal_uInt8[ nBufLen ];
    memset(pBuffer, 0, nBufLen);

    rtlRandomError aError = rtl_random_getBytes(NULL, NULL, 0);
    ASSERT_TRUE(aError == rtl_Random_E_Argument) << "wrong parameter";

    /* rtlRandomError */ aError = rtl_random_getBytes(aPool, NULL, 0);
    ASSERT_TRUE(aError == rtl_Random_E_Argument) << "wrong parameter";

    /* rtlRandomError */ aError = rtl_random_getBytes(aPool, pBuffer, nBufLen);
    ASSERT_TRUE(aError == rtl_Random_E_None) << "wrong parameter";

    rtl_random_destroyPool(aPool);
    delete [] pBuffer;
}

TEST_F(getBytes, getBytes_001)
{
    rtlRandomPool aPool = rtl_random_createPool();

    sal_uInt32  nBufLen = 4;
    sal_uInt8   *pBuffer = new sal_uInt8[ nBufLen ];
    memset(pBuffer, 0, nBufLen);

    rtlRandomError aError = rtl_random_getBytes(aPool, pBuffer, nBufLen);
    ASSERT_TRUE(aError == rtl_Random_E_None) << "wrong parameter";

    printf("%2x %2x %2x %2x\n", pBuffer[0], pBuffer[1], pBuffer[2], pBuffer[3]);

    rtl_random_destroyPool(aPool);
    delete [] pBuffer;
}

TEST_F(getBytes, getBytes_002)
{
    rtlRandomPool aPool = rtl_random_createPool();

    sal_uInt32  nBufLen = 4;
    sal_uInt8   *pBuffer = new sal_uInt8[ nBufLen << 1 ];
    memset(pBuffer, 0, nBufLen << 1);

    ASSERT_TRUE(pBuffer[4] == 0 && pBuffer[5] == 0 && pBuffer[6] == 0 && pBuffer[7] == 0) << "memset failed";

    rtlRandomError aError = rtl_random_getBytes(aPool, pBuffer, nBufLen);
    ASSERT_TRUE(aError == rtl_Random_E_None) << "wrong parameter";

    printf("%2x %2x %2x %2x %2x %2x %2x %2x\n", pBuffer[0], pBuffer[1], pBuffer[2], pBuffer[3], pBuffer[4], pBuffer[5], pBuffer[6], pBuffer[7]);

    ASSERT_TRUE(pBuffer[4] == 0 && pBuffer[5] == 0 && pBuffer[6] == 0 && pBuffer[7] == 0) << "internal memory overwrite";

    rtl_random_destroyPool(aPool);
    delete [] pBuffer;
}

TEST_F(getBytes, getBytes_003)
{
    rtlRandomPool aPool = rtl_random_createPool();

    sal_uInt32  nBufLen = 1;
    sal_uInt8   *pBuffer = new sal_uInt8[ nBufLen ];
    memset(pBuffer, 0, nBufLen);

    Statistics aStat;

    ASSERT_TRUE(pBuffer[0] == 0) << "memset failed";

    int nCount = 0;

    int nCountMax = 1000000;
    for(nCount = 0;nCount < nCountMax; nCount ++)                  // run 100000000 through getBytes(...)
    {
        /* rtlRandomError aError = */ rtl_random_getBytes(aPool, pBuffer, nBufLen);
        /* ASSERT_TRUE(aError == rtl_Random_E_None); << "wrong parameter" */

        aStat.addValue(pBuffer[0], 1);
    }

    aStat.build(nCountMax);
    aStat.print();

    ASSERT_TRUE(aStat.getMaxDeviation() < aStat.getAverage()) << "deviation should be less average";

    rtl_random_destroyPool(aPool);
    delete [] pBuffer;
}

TEST_F(getBytes, getBytes_003_1)
{
    rtlRandomPool aPool = rtl_random_createPool();

    sal_uInt32  nBufLen = 256;
    sal_uInt8   *pBuffer = new sal_uInt8[ nBufLen ];
    memset(pBuffer, 0, nBufLen);

    Statistics aStat;

    ASSERT_TRUE(pBuffer[0] == 0) << "memset failed";

    int nCount = 0;

    int nCountMax = 10000;
    for(nCount = 0;nCount < nCountMax; nCount ++)                  // run 100000000 through getBytes(...)
    {
        /* rtlRandomError aError = */ rtl_random_getBytes(aPool, pBuffer, nBufLen);
        // ASSERT_TRUE(aError == rtl_Random_E_None) << "wrong parameter"";

        for (sal_uInt32 i=0;i<nBufLen;i++)
        {
            aStat.addValue(pBuffer[i], 1);
        }
    }

    aStat.build(nCountMax * nBufLen);
    aStat.print();

    ASSERT_TRUE(aStat.getMaxDeviation() < aStat.getAverage()) << "deviation should be less average";

    rtl_random_destroyPool(aPool);
    delete [] pBuffer;
}

// -----------------------------------------------------------------------------
} // namespace rtl_random

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
