<commit_before>/*
 * AresBWAPIBot : A bot for SC:BW using BWAPI library;
 * Copyright (C) 2015 <NAME>; <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "Trace.h"
#include "Logger.h"
#include "Utils.h"
#include <boost/format.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <ctime>
#include <future>
#include <list>
#include <random>

namespace
{

const unsigned int THREADS_COUNT = 20;
const unsigned int TRACES_PER_THREAD = 1000;
const unsigned int INFO_THREADS_COUNT = THREADS_COUNT / 3;

const std::string SEPARATOR_REGEX = " \\| ";
const std::string DATE_REGEX = "[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}";
const std::string LEVEL_REGEX = "(DEBUG|INFO|WARNING|ERROR)";
const std::string AUXILIARY_LEVEL_REGEX = "(WARNING|ERROR)";
const std::string LOCATION_REGEX = "[^:]+:[0-9]+";
const std::string TEST_MESSAGE_TEMPLATE = "test message n°%1% from thread %2%";
const std::string TEST_MESSAGE_REGEX = boost::str(boost::format(TEST_MESSAGE_TEMPLATE) % "[0-9]+" % "[0-9]+");
const std::string completeLayoutRegex(DATE_REGEX + SEPARATOR_REGEX
                                      + LEVEL_REGEX + SEPARATOR_REGEX
                                      + LOCATION_REGEX + SEPARATOR_REGEX
                                      + TEST_MESSAGE_REGEX + "\n?");
const std::string basicLayoutRegex(LEVEL_REGEX + " : " + TEST_MESSAGE_REGEX + "\n?");

decltype(ARES_INFO()) stream(int type)
{
    if (type == 0) return ARES_INFO();
    if (type == 1) return ARES_WARNING();
    return ARES_ERROR();
}

void loopTrace(int type)
{
    auto&& threadId = std::this_thread::get_id();
    for (int i = 1; i <= TRACES_PER_THREAD; ++i)
    {
        stream(type) << boost::format(TEST_MESSAGE_TEMPLATE) % i % threadId;
    }
}

class MockLogger : public trace::AbstractLogger
{
    public:
        MOCK_METHOD2(log, void(const trace::LogContext&, const std::string&));
};

class EncapsulatedLogger : public trace::AbstractLogger
{
    public:
        EncapsulatedLogger(trace::AbstractLogger& logger)
            : m_logger(logger)
        {}

        void log(const trace::LogContext& context, const std::string& message) override {
            m_logger.log(context, message);
        }

    private:
        trace::AbstractLogger& m_logger;
};

}

TEST(CoreTraceTest, TracesLayoutAuxiliaryLoggerAndThreadSafe)
{
    // Set the auxiliary logger to a mock object and expect calls on it (info traces are not logged into auxiliary)
    MockLogger mockLogger;
    trace::Facade::initializeAuxiliaryLogger<EncapsulatedLogger>(mockLogger);
#if GTEST_USES_POSIX_RE
    auto auxiliaryMessageMatcher = ::testing::MatchesRegex(basicLayoutRegex);
#else
    auto auxiliaryMessageMatcher = ::testing::_;
#endif
    EXPECT_CALL(mockLogger, log(::testing::_, auxiliaryMessageMatcher))
        .Times((THREADS_COUNT - INFO_THREADS_COUNT) * TRACES_PER_THREAD);

    // Start threads that will trace
    std::list<std::future<void>> futureList;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(1, 2);
    for (int i = 0; i < THREADS_COUNT; ++i) {
        int type = 0;
        // The first INFO_THREADS_COUNT threads will log only info traces, the rest will choose between warning and error
        if (i >= INFO_THREADS_COUNT) {
            type = dis(gen);
        }
        futureList.push_back(std::move(std::async(std::launch::async, loopTrace, type)));
    }
    futureList.clear();

    // Open the log output
    std::ifstream logFile;
    logFile.open(utils::homePath() + std::string("/AresBWAPI.log"));

    // Read each line and check if they match the layout
    std::string line;
    unsigned int count = 0;
    while (std::getline(logFile, line))
    {
#if GTEST_USES_POSIX_RE
        ASSERT_THAT(line, ::testing::MatchesRegex(completeLayoutRegex));
#endif
        ++count;
    }

    // Check that we have the right count of lines
    EXPECT_EQ(THREADS_COUNT * TRACES_PER_THREAD, count);
}

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

<commit_msg>Fixed a bug in trace test on visual studio 2012<commit_after>/*
 * AresBWAPIBot : A bot for SC:BW using BWAPI library;
 * Copyright (C) 2015 <NAME>; <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "Trace.h"
#include "Logger.h"
#include "Utils.h"
#include <boost/format.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <ctime>
#include <future>
#include <list>
#include <random>

namespace
{

const unsigned int THREADS_COUNT = 20;
const unsigned int TRACES_PER_THREAD = 1000;
const unsigned int INFO_THREADS_COUNT = THREADS_COUNT / 3;

const std::string SEPARATOR_REGEX = " \\| ";
const std::string DATE_REGEX = "[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}";
const std::string LEVEL_REGEX = "(DEBUG|INFO|WARNING|ERROR)";
const std::string AUXILIARY_LEVEL_REGEX = "(WARNING|ERROR)";
const std::string LOCATION_REGEX = "[^:]+:[0-9]+";
const std::string TEST_MESSAGE_TEMPLATE = "test message n°%1% from thread %2%";
const std::string TEST_MESSAGE_REGEX = boost::str(boost::format(TEST_MESSAGE_TEMPLATE) % "[0-9]+" % "[0-9]+");
const std::string completeLayoutRegex(DATE_REGEX + SEPARATOR_REGEX
                                      + LEVEL_REGEX + SEPARATOR_REGEX
                                      + LOCATION_REGEX + SEPARATOR_REGEX
                                      + TEST_MESSAGE_REGEX + "\n?");
const std::string basicLayoutRegex(LEVEL_REGEX + " : " + TEST_MESSAGE_REGEX + "\n?");

decltype(ARES_INFO()) stream(int type)
{
    if (type == 0) return ARES_INFO();
    if (type == 1) return ARES_WARNING();
    return ARES_ERROR();
}

void loopTrace(int type)
{
    auto&& threadId = std::this_thread::get_id();
    for (int i = 1; i <= TRACES_PER_THREAD; ++i)
    {
        stream(type) << boost::format(TEST_MESSAGE_TEMPLATE) % i % threadId;
    }
}

class MockLogger : public trace::AbstractLogger
{
    public:
        MOCK_METHOD2(log, void(const trace::LogContext&, const std::string&));
};

class EncapsulatedLogger : public trace::AbstractLogger
{
    public:
        EncapsulatedLogger(trace::AbstractLogger& logger)
            : m_logger(logger)
        {}

        void log(const trace::LogContext& context, const std::string& message) override {
            m_logger.log(context, message);
        }

    private:
        trace::AbstractLogger& m_logger;
};

}

TEST(CoreTraceTest, TracesLayoutAuxiliaryLoggerAndThreadSafe)
{
    // Set the auxiliary logger to a mock object and expect calls on it (info traces are not logged into auxiliary)
    MockLogger mockLogger;
    trace::Facade::initializeAuxiliaryLogger<EncapsulatedLogger>(mockLogger);
#if GTEST_USES_POSIX_RE
    auto auxiliaryMessageMatcher = ::testing::MatchesRegex(basicLayoutRegex);
#else
    auto auxiliaryMessageMatcher = ::testing::_;
#endif
    EXPECT_CALL(mockLogger, log(::testing::_, auxiliaryMessageMatcher))
        .Times((THREADS_COUNT - INFO_THREADS_COUNT) * TRACES_PER_THREAD);

    // Start threads that will trace
    std::list<std::future<void>> futureList;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(1, 2);
    for (int i = 0; i < THREADS_COUNT; ++i) {
        int type = 0;
        // The first INFO_THREADS_COUNT threads will log only info traces, the rest will choose between warning and error
        if (i >= INFO_THREADS_COUNT) {
            type = dis(gen);
        }
        futureList.push_back(std::move(std::async(std::launch::async, loopTrace, type)));
    }

    /* Wait for all threads to end (note: on visual studio 2012, the destructor of std::future
       does not block as it should, this is a bug. Instead we have to call wait explicitly) */
    for (auto&& future : futureList) {
        future.wait();
    }

    // Open the log output
    std::ifstream logFile;
    logFile.open(utils::homePath() + std::string("/AresBWAPI.log"));

    // Read each line and check if they match the layout
    std::string line;
    unsigned int count = 0;
    while (std::getline(logFile, line))
    {
#if GTEST_USES_POSIX_RE
        ASSERT_THAT(line, ::testing::MatchesRegex(completeLayoutRegex));
#endif
        ++count;
    }

    // Check that we have the right count of lines
    EXPECT_EQ(THREADS_COUNT * TRACES_PER_THREAD, count);
}

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


{'fraction_non_alphanumeric': 0.12066686998068517, 'fraction_numerical': 0.013825353258107147, 'mean_word_length': 3.5715613382899627, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1977868', 'n_tokens_mistral': 3164, 'n_tokens_neox': 3041, 'n_words': 895}