<commit_before>/** @file testing layer z class
 * Test coverage will be distributed into the following:
 * test layer initialization using fixutres
 * test layer parameter validation using value-parameterized tests
 * test layer application with fake input data using fixtures
 *
 * in order to define a common base test class and utilize different
 * gtest test fixutres as well as value-parameterization we'll define
 * the a bast class for testing in the form of a mixin.
 */
#include "layers/layer_z.h"

#include "core/exception.h"
#include "core/mat_utils.h"
#include "core/ptree_utils.h"
#include "core/signal.h"
#include "ts/ts.h"
#include "ts/fakeevidence.h"

using namespace std;
using namespace cv;
using namespace sem;

// name of keys in signal
const string NAME_INPUT_SPIKES   = "in";        ///< no. of afferent spikes
const string NAME_OUTPUT_SPIKES  = "out";       ///< no. of output spikes/size of output layer
const string NAME_OUTPUT_MEM_POT = "mem_pot";   ///< membrane potential
const string NAME_OUTPUT_WEIGHTS = "weights";   ///< neuron weights
const string NAME_OUTPUT_BIAS    = "bias";         ///< neuron weights

/**
 * @brief mixin for testing layer Z, the main, SEM learning algorithm
 * Because we expect to test using fixutres as well as parametrized tests
 * Since these two test types are derived differently mixins solves the problem of defining a common base
 * The solution is adopted from this StackOverflow post:
 * @see http://stackoverflow.com/questions/3152326/google-test-parameterized-tests-which-use-an-existing-test-fixture-class
 *
 * T specifies test type (fixture or parameterized)
 */
template <class T> class LayerZTestBase : public T
{
protected:
    virtual void SetUp()
    {
        nb_afferents_ = 50;
        params_ = PTree();
        params_.put(LayerZ::PARAM_NB_AFFERENTS, nb_afferents_);
        params_.put(LayerZ::PARAM_NB_OUTPUT_NODES, 10);
        config_.Params(params_);

        // IO
        config_.Input(LayerZ::KEY_INPUT_SPIKES, NAME_INPUT_SPIKES);

        config_.Output(LayerZ::KEY_OUTPUT_SPIKES, NAME_OUTPUT_SPIKES);
        config_.Output(LayerZ::KEY_OUTPUT_MEMBRANE_POT, NAME_OUTPUT_MEM_POT);
    }

    // members
    LayerConfig config_;    ///< default layer configuration
    PTree params_;          ///< default params

    int nb_afferents_;
};

/**
 * @brief class for testing layer z initialization routines
 */
class LayerZInitTest : public LayerZTestBase<testing::Test >
{
protected:
};

/**
 * @brief test validation of missing params
 */
TEST_F(LayerZInitTest, MissingParams)
{
    // remove key to output nodes
    params_.erase(LayerZ::PARAM_NB_OUTPUT_NODES);
    config_.Params(params_);

    EXPECT_THROW(LayerZ().Reset(config_), std::exception);
}

TEST_F(LayerZInitTest, IONames)
{
    LayerConfig cfg;
    cfg.Params(config_.Params());
    EXPECT_THROW(LayerZ().IONames(cfg), std::exception);

    cfg.Input(LayerZ::KEY_INPUT_SPIKES, NAME_INPUT_SPIKES);
    EXPECT_THROW(LayerZ().IONames(cfg), std::exception) << "still missing required output spikes";

    cfg.Output(LayerZ::KEY_OUTPUT_SPIKES, NAME_OUTPUT_SPIKES);
    EXPECT_NO_THROW(LayerZ().IONames(cfg)) << "Are all required IO names present?";
}

typedef std::pair<std::string, float > TParamPairSF; /// convinience typdef to use as test params below

/**
 * @brief Parameterized test for testing layer z parameter value validation
 * Using paramterized tests allows us to try different value more easily
 */
class LayerZParamsTest : public LayerZTestBase<testing::TestWithParam<TParamPairSF > >
{
protected:
};

/**
 * @brief use macro for instantiating value-parameterized test
 * if you're using QTCreator, don't mind the ..._EvalGenerator_ warning at the bottom
 */<commit_msg>use LayerIONames instead of LayerConfig<commit_after>/** @file testing layer z class
 * Test coverage will be distributed into the following:
 * test layer initialization using fixutres
 * test layer parameter validation using value-parameterized tests
 * test layer application with fake input data using fixtures
 *
 * in order to define a common base test class and utilize different
 * gtest test fixutres as well as value-parameterization we'll define
 * the a bast class for testing in the form of a mixin.
 */
#include "layers/layer_z.h"

#include "core/exception.h"
#include "core/mat_utils.h"
#include "core/ptree_utils.h"
#include "core/signal.h"
#include "ts/ts.h"
#include "ts/fakeevidence.h"

using namespace std;
using namespace cv;
using namespace sem;

// name of keys in signal
const string NAME_INPUT_SPIKES   = "in";        ///< no. of afferent spikes
const string NAME_OUTPUT_SPIKES  = "out";       ///< no. of output spikes/size of output layer
const string NAME_OUTPUT_MEM_POT = "mem_pot";   ///< membrane potential
const string NAME_OUTPUT_WEIGHTS = "weights";   ///< neuron weights
const string NAME_OUTPUT_BIAS    = "bias";         ///< neuron weights

/**
 * @brief mixin for testing layer Z, the main, SEM learning algorithm
 * Because we expect to test using fixutres as well as parametrized tests
 * Since these two test types are derived differently mixins solves the problem of defining a common base
 * The solution is adopted from this StackOverflow post:
 * @see http://stackoverflow.com/questions/3152326/google-test-parameterized-tests-which-use-an-existing-test-fixture-class
 *
 * T specifies test type (fixture or parameterized)
 */
template <class T> class LayerZTestBase : public T
{
protected:
    virtual void SetUp()
    {
        nb_afferents_ = 50;
        params_ = PTree();
        params_.put(LayerZ::PARAM_NB_AFFERENTS, nb_afferents_);
        params_.put(LayerZ::PARAM_NB_OUTPUT_NODES, 10);
        config_.Params(params_);

        // IO
        config_.Input(LayerZ::KEY_INPUT_SPIKES, NAME_INPUT_SPIKES);

        config_.Output(LayerZ::KEY_OUTPUT_SPIKES, NAME_OUTPUT_SPIKES);
        config_.Output(LayerZ::KEY_OUTPUT_MEMBRANE_POT, NAME_OUTPUT_MEM_POT);
    }

    // members
    LayerConfig config_;    ///< default layer configuration
    PTree params_;          ///< default params

    int nb_afferents_;
};

/**
 * @brief class for testing layer z initialization routines
 */
class LayerZInitTest : public LayerZTestBase<testing::Test >
{
protected:
};

/**
 * @brief test validation of missing params
 */
TEST_F(LayerZInitTest, MissingParams)
{
    // remove key to output nodes
    params_.erase(LayerZ::PARAM_NB_OUTPUT_NODES);
    config_.Params(params_);

    EXPECT_THROW(LayerZ().Reset(config_), std::exception);
}

TEST_F(LayerZInitTest, IONames)
{
    LayerIONames io_names;
    EXPECT_THROW(LayerZ().IONames(io_names), std::exception);

    io_names.Input(LayerZ::KEY_INPUT_SPIKES, NAME_INPUT_SPIKES);
    EXPECT_THROW(LayerZ().IONames(io_names), std::exception) << "still missing required output spikes";

    io_names.Output(LayerZ::KEY_OUTPUT_SPIKES, NAME_OUTPUT_SPIKES);
    EXPECT_NO_THROW(LayerZ().IONames(io_names)) << "Are all required IO names present?";
}

typedef std::pair<std::string, float > TParamPairSF; /// convinience typdef to use as test params below

/**
 * @brief Parameterized test for testing layer z parameter value validation
 * Using paramterized tests allows us to try different value more easily
 */
class LayerZParamsTest : public LayerZTestBase<testing::TestWithParam<TParamPairSF > >
{
protected:
};

/**
 * @brief use macro for instantiating value-parameterized test
 * if you're using QTCreator, don't mind the ..._EvalGenerator_ warning at the bottom
 */
{'fraction_non_alphanumeric': 0.09891870244293152, 'fraction_numerical': 0.002936857562408223, 'mean_word_length': 4.048517520215634, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2966623', 'n_tokens_mistral': 2329, 'n_tokens_neox': 2214, 'n_words': 685}