/**
 * @file LogFilterTest.h
 * @author Bartosz Janiak
 * 
 * @brief
 *
 * Copyright © 2009 NVIDIA Corporation. All rights reserved.
 *
 * NVIDIA Corporation and its licensors retain all intellectual property and proprietary
 * rights in and to this software, related documentation and any modifications thereto. Any
 * use, reproduction, disclosure or distribution of this software and related documentation
 * without express license agreement from NVIDIA Corporation is strictly prohibited.
 */

#pragma once
#include "MockWinApi.h"
#include "cxxtest/TestSuite.h"
#include "TestObjects.h"
#include <Logging.h>
#include <boost/assign/std/vector.hpp>

namespace Nvidia {
namespace Logging {
namespace Test {

using namespace boost::assign; // bring 'operator+=()' into scope

class LogFilterTest : public CxxTest::TestSuite
{
public:
    std::vector<LogLevel> m_LogLevelOrder;
    
    void setUp()
    {
        m_LogLevelOrder += LogLevel_Quiet, LogLevel_System, LogLevel_Critical, LogLevel_Error, LogLevel_Warning, LogLevel_Debug, LogLevel_Info;
    }

    void TestSimpleLogFilter()
    {
        unsigned int filterNum, levelNum;
        std::tstring emptyString;

        for ( filterNum = 0 ; filterNum < m_LogLevelOrder.size() ; filterNum++ )
        {
            LogFilter logFilter(m_LogLevelOrder[filterNum]);
            for ( levelNum = 0 ; levelNum < m_LogLevelOrder.size() ; levelNum++ )
            {
                TS_ASSERT_EQUALS(logFilter.IsFiltered(LogInfo(m_LogLevelOrder[levelNum], emptyString, _T(""), _T(""), 0)), levelNum > filterNum);
            }
        }
    }
    
    /*
    default = 0
    "One"=dword:00000003
    "Two"=dword:00000005
    "Two.B"=dword:00000002
    "Three"=dword:00000001
    "Three.C"=dword:00000004
    "Four.D.1234.!@#$%^&*()-+"=dword:00000004
    */
    
    void CheckRegistryLogFilter(LogFilter& logFilter)
    {
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("One")), LogLevel_Warning);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Two")), LogLevel_Info);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Two.B")), LogLevel_Error);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Three")), LogLevel_Critical);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Three.C")), LogLevel_Debug);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Four.D.1234.!@#$%^&*()-+")), LogLevel_Debug);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("")), LogLevel_System);
    }

    void CheckRegistryLogFilterChildren(LogFilter& logFilter)
    {
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("One.UnderOne")), LogLevel_Warning);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Two.UnderTwoNotB")), LogLevel_Info);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Two.B.UnderB")), LogLevel_Error);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Two.B.UnderB.MoreUnderB")), LogLevel_Error);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Three.NotC")), LogLevel_Critical);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Three.C.UnderC.MoreUnderC")), LogLevel_Debug);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Three.C.UnderC")), LogLevel_Debug);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Four.D.1234.!@#$%^&*()-+.UnderGibberish")), LogLevel_Debug);
    }

    void CheckRegistryLogFilterTricky(LogFilter& logFilter)
    {
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Four.D")), LogLevel_System);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Three.CCC")), LogLevel_Critical);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Four.D.1234.!@#$%^&*()")), LogLevel_System);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("aTwo.B")), LogLevel_System);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Twoa.B")), LogLevel_System);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("Two.Two.B")), LogLevel_Info);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T(" ")), LogLevel_System);
        TS_ASSERT_EQUALS(logFilter.GetMaximumLogLevel(_T("                                     ")), LogLevel_System);
    }

    void CheckRegistryLogFilterIsFiltered(LogFilter& logFilter)
    {
        std::tstring origin(_T("Two.B.foo.bar.foo.bar"));
        TS_ASSERT_EQUALS(logFilter.IsFiltered(LogInfo(LogLevel_Error, origin, _T(""), _T(""), 0)), false);
        TS_ASSERT_EQUALS(logFilter.IsFiltered(LogInfo(LogLevel_Warning, origin, _T(""), _T(""), 0)), true);
    }

    LogFilter CreateRegistryLogFilter()
    {
        RegistryKey key = RegistryKey(HKEY_LOCAL_MACHINE).GetSubKey(_T("Software")).GetSubKey(_T("NVIDIA Corporation")).GetSubKey(_T("Logging")).
            GetSubKey(_T("Definitions")).GetSubKey(_T("LogFilters")).GetSubKey(_T("TestFilter"));

        return LogFilter(key);
    }

    void TestRegistryLogFilter1()
    {
        LogFilter logFilter = CreateRegistryLogFilter();

        CheckRegistryLogFilter(logFilter);
        CheckRegistryLogFilterChildren(logFilter);
        CheckRegistryLogFilterTricky(logFilter);
        CheckRegistryLogFilterIsFiltered(logFilter);
    }

    void TestRegistryLogFilter2()
    {
        LogFilter logFilter = CreateRegistryLogFilter();
        
        CheckRegistryLogFilterTricky(logFilter);
        CheckRegistryLogFilterChildren(logFilter);
        CheckRegistryLogFilter(logFilter);
        CheckRegistryLogFilterIsFiltered(logFilter);
    }

    void TestRegistryLogFilter3()
    {
        LogFilter logFilter = CreateRegistryLogFilter();
        
        CheckRegistryLogFilterIsFiltered(logFilter);
        CheckRegistryLogFilterChildren(logFilter);
        CheckRegistryLogFilterTricky(logFilter);
        CheckRegistryLogFilter(logFilter);
    }

};

}
}
}

using namespace Nvidia::Logging::Test;