<commit_before>//
// Unit tests for denial-of-service detection/prevention code
//
#include <algorithm>

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>

#include "main.h"
#include "wallet.h"
#include "net.h"
#include "util.h"

#include <stdint.h>

// Tests this internal-to-main.cpp method:
extern bool AddOrphanTx(const CDataStream& vMsg);
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
extern std::map<uint256, CDataStream*> mapOrphanTransactions;
extern std::map<uint256, std::map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;

CService ip(uint32_t i)
{
    struct in_addr s;
    s.s_addr = i;
    return CService(CNetAddr(s), GetDefaultPort());
}

BOOST_AUTO_TEST_SUITE(DoS_tests)

BOOST_AUTO_TEST_CASE(DoS_banning)
{
    CNode::ClearBanned();
    CAddress addr1(ip(0xa0b0c001));
    CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
    dummyNode1.Misbehaving(100); // Should get banned
    BOOST_CHECK(CNode::IsBanned(addr1));
    BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different ip, not banned

    CAddress addr2(ip(0xa0b0c002));
    CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
    dummyNode2.Misbehaving(50);
    BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
    BOOST_CHECK(CNode::IsBanned(addr1));  // ... but 1 still should be
    dummyNode2.Misbehaving(50);
    BOOST_CHECK(CNode::IsBanned(addr2));
}

BOOST_AUTO_TEST_CASE(DoS_banscore)
{
    CNode::ClearBanned();
    mapArgs["-banscore"] = "111"; // because 11 is my favorite number
    CAddress addr1(ip(0xa0b0c001));
    CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
    dummyNode1.Misbehaving(100);
    BOOST_CHECK(!CNode::IsBanned(addr1));
    dummyNode1.Misbehaving(10);
    BOOST_CHECK(!CNode::IsBanned(addr1));
    dummyNode1.Misbehaving(1);
    BOOST_CHECK(CNode::IsBanned(addr1));
    mapArgs.erase("-banscore");
}

BOOST_AUTO_TEST_CASE(DoS_bantime)
{
    CNode::ClearBanned();
    int64 nStartTime = GetTime();
    SetMockTime(nStartTime); // Overrides future calls to GetTime()

    CAddress addr(ip(0xa0b0c001));
    CNode dummyNode(INVALID_SOCKET, addr, "", true);

    dummyNode.Misbehaving(100);
    BOOST_CHECK(CNode::IsBanned(addr));

    SetMockTime(nStartTime+60*60);
    BOOST_CHECK(CNode::IsBanned(addr));

    SetMockTime(nStartTime+60*60*24+1);
    BOOST_CHECK(!CNode::IsBanned(addr));
}

static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)\
{
    if (time1 > time2)
        return CheckNBits(nbits2, time2, nbits1, time1);
    int64 deltaTime = time2-time1;

    CBigNum required;
    required.SetCompact(ComputeMinWork(nbits1, deltaTime, false));
    CBigNum have;
    have.SetCompact(nbits2);
    return (have <= required);
}

CTransaction RandomOrphan()
{
    std::map<uint256, CDataStream*>::iterator it;
    it = mapOrphanTransactions.lower_bound(GetRandHash());
    if (it == mapOrphanTransactions.end())
        it = mapOrphanTransactions.begin();
    const CDataStream* pvMsg = it->second;
    CTransaction tx;
    CDataStream(*pvMsg) >> tx;
    return tx;
}

BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{
    CKey key;
    key.MakeNewKey(true);
    CBasicKeyStore keystore;
    keystore.AddKey(key);

    // 50 orphan transactions:
    for (int i = 0; i < 50; i++)
    {
        CTransaction tx;
        tx.vin.resize(1);
        tx.vin[0].prevout.n = 0;
        tx.vin[0].prevout.hash = GetRandHash();
        tx.vin[0].scriptSig << OP_1;
        tx.vout.resize(1);
        tx.vout[0].nValue = 1*CENT;
        tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());

        CDataStream ds(SER_DISK, CLIENT_VERSION);
        ds << tx;
        AddOrphanTx(ds);
    }

    // ... and 50 that depend on other orphans:
    for (int i = 0; i < 50; i++)
    {
        CTransaction txPrev = RandomOrphan();

        CTransaction tx;
        tx.vin.resize(1);
        tx.vin[0].prevout.n = 0;
        tx.vin[0].prevout.hash = txPrev.GetHash();
        tx.vout.resize(1);
        tx.vout[0].nValue = 1*CENT;
        tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
        SignSignature(keystore, txPrev, tx, 0);

        CDataStream ds(SER_DISK, CLIENT_VERSION);
        ds << tx;
        AddOrphanTx(ds);
    }

    // This really-big orphan should be ignored:
    for (int i = 0; i < 10; i++)
    {
        CTransaction txPrev = RandomOrphan();

        CTransaction tx;
        tx.vout.resize(1);
        tx.vout[0].nValue = 1*CENT;
        tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
        tx.vin.resize(500);
        for (int j = 0; j < tx.vin.size(); j++)
        {
            tx.vin[j].prevout.n = j;
            tx.vin[j].prevout.hash = txPrev.GetHash();
        }
        SignSignature(keystore, txPrev, tx, 0);
        // Re-use same signature for other inputs
        // (they don't have to be valid for this test)
        for (int j = 1; j < tx.vin.size(); j++)
            tx.vin[j].scriptSig = tx.vin[0].scriptSig;

        CDataStream ds(SER_DISK, CLIENT_VERSION);
        ds << tx;
        BOOST_CHECK(!AddOrphanTx(ds));
    }

    // Test LimitOrphanTxSize() function:
    LimitOrphanTxSize(40);
    BOOST_CHECK(mapOrphanTransactions.size() <= 40);
    LimitOrphanTxSize(10);
    BOOST_CHECK(mapOrphanTransactions.size() <= 10);
    LimitOrphanTxSize(0);
    BOOST_CHECK(mapOrphanTransactions.empty());
    BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
}

BOOST_AUTO_TEST_CASE(DoS_checkSig)
{
    // Test signature caching code (see key.cpp Verify() methods)

    CKey key;
    key.MakeNewKey(true);
    CBasicKeyStore keystore;
    keystore.AddKey(key);

    // 100 orphan transactions:
    static const int NPREV=100;
    CTransaction orphans[NPREV];
    for (int i = 0; i < NPREV; i++)
    {
        CTransaction& tx = orphans[i];
        tx.vin.resize(1);
        tx.vin[0].prevout.n = 0;
        tx.vin[0].prevout.hash = GetRandHash();
        tx.vin[0].scriptSig << OP_1;
        tx.vout.resize(1);
        tx.vout[0].nValue = 1*CENT;
        tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());

        CDataStream ds(SER_DISK, CLIENT_VERSION);
        ds << tx;
        AddOrphanTx(ds);
    }

    // Create a transaction that depends on orphans:
    CTransaction tx;
    tx.vout.resize(1);
    tx.vout[0].nValue = 1*CENT;
    tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
    tx.vin.resize(NPREV);
    for (int j = 0; j < tx.vin.size(); j++)
    {
        tx.vin[j].prevout.n = 0;
        tx.vin[j].prevout.hash = orphans[j].GetHash();
    }
    // Creating signatures primes the cache:
    boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time();
    for (int j = 0; j < tx.vin.size(); j++)
        BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j));
    boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time();
    boost::posix_time::time_duration msdiff = mst2 - mst1;
    long nOneValidate = msdiff.total_milliseconds();
    if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate);

    // ... now validating repeatedly should be quick:
    // 2.8GHz machine, -g build: Sign takes ~760ms,
    // uncached Verify takes ~250ms, cached Verify takes ~50ms
    // (for 100 single-signature inputs)
    mst1 = boost::posix_time::microsec_clock::local_time();
    for (int i = 0; i < 5; i++)
        for (int j = 0; j < tx.vin.size(); j++)
            BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
    mst2 = boost::posix_time::microsec_clock::local_time();
    msdiff = mst2 - mst1;
    long nManyValidate = msdiff.total_milliseconds();
    if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate);

    BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");

    // Empty a signature, validation should fail:
    CScript save = tx.vin[0].scriptSig;
    tx.vin[0].scriptSig = CScript();
    BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
    tx.vin[0].scriptSig = save;

    // Swap signatures, validation should fail:
    std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
    BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
    BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL));
    std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);

    // Exercise -maxsigcachesize code:
    mapArgs["-maxsigcachesize"] = "10";
    // Generate a new, different signature for vin[0] to trigger cache clear:
    CScript oldSig = tx.vin[0].scriptSig;
    BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
    BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
    for (int j = 0; j < tx.vin.size(); j++)
        BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
    mapArgs.erase("-maxsigcachesize");

    LimitOrphanTxSize(0);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Remove the rest of the unneeded checknbits test.<commit_after>//
// Unit tests for denial-of-service detection/prevention code
//
#include <algorithm>

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>

#include "main.h"
#include "wallet.h"
#include "net.h"
#include "util.h"

#include <stdint.h>

// Tests this internal-to-main.cpp method:
extern bool AddOrphanTx(const CDataStream& vMsg);
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
extern std::map<uint256, CDataStream*> mapOrphanTransactions;
extern std::map<uint256, std::map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;

CService ip(uint32_t i)
{
    struct in_addr s;
    s.s_addr = i;
    return CService(CNetAddr(s), GetDefaultPort());
}

BOOST_AUTO_TEST_SUITE(DoS_tests)

BOOST_AUTO_TEST_CASE(DoS_banning)
{
    CNode::ClearBanned();
    CAddress addr1(ip(0xa0b0c001));
    CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
    dummyNode1.Misbehaving(100); // Should get banned
    BOOST_CHECK(CNode::IsBanned(addr1));
    BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different ip, not banned

    CAddress addr2(ip(0xa0b0c002));
    CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
    dummyNode2.Misbehaving(50);
    BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
    BOOST_CHECK(CNode::IsBanned(addr1));  // ... but 1 still should be
    dummyNode2.Misbehaving(50);
    BOOST_CHECK(CNode::IsBanned(addr2));
}

BOOST_AUTO_TEST_CASE(DoS_banscore)
{
    CNode::ClearBanned();
    mapArgs["-banscore"] = "111"; // because 11 is my favorite number
    CAddress addr1(ip(0xa0b0c001));
    CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
    dummyNode1.Misbehaving(100);
    BOOST_CHECK(!CNode::IsBanned(addr1));
    dummyNode1.Misbehaving(10);
    BOOST_CHECK(!CNode::IsBanned(addr1));
    dummyNode1.Misbehaving(1);
    BOOST_CHECK(CNode::IsBanned(addr1));
    mapArgs.erase("-banscore");
}

BOOST_AUTO_TEST_CASE(DoS_bantime)
{
    CNode::ClearBanned();
    int64 nStartTime = GetTime();
    SetMockTime(nStartTime); // Overrides future calls to GetTime()

    CAddress addr(ip(0xa0b0c001));
    CNode dummyNode(INVALID_SOCKET, addr, "", true);

    dummyNode.Misbehaving(100);
    BOOST_CHECK(CNode::IsBanned(addr));

    SetMockTime(nStartTime+60*60);
    BOOST_CHECK(CNode::IsBanned(addr));

    SetMockTime(nStartTime+60*60*24+1);
    BOOST_CHECK(!CNode::IsBanned(addr));
}

CTransaction RandomOrphan()
{
    std::map<uint256, CDataStream*>::iterator it;
    it = mapOrphanTransactions.lower_bound(GetRandHash());
    if (it == mapOrphanTransactions.end())
        it = mapOrphanTransactions.begin();
    const CDataStream* pvMsg = it->second;
    CTransaction tx;
    CDataStream(*pvMsg) >> tx;
    return tx;
}

BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{
    CKey key;
    key.MakeNewKey(true);
    CBasicKeyStore keystore;
    keystore.AddKey(key);

    // 50 orphan transactions:
    for (int i = 0; i < 50; i++)
    {
        CTransaction tx;
        tx.vin.resize(1);
        tx.vin[0].prevout.n = 0;
        tx.vin[0].prevout.hash = GetRandHash();
        tx.vin[0].scriptSig << OP_1;
        tx.vout.resize(1);
        tx.vout[0].nValue = 1*CENT;
        tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());

        CDataStream ds(SER_DISK, CLIENT_VERSION);
        ds << tx;
        AddOrphanTx(ds);
    }

    // ... and 50 that depend on other orphans:
    for (int i = 0; i < 50; i++)
    {
        CTransaction txPrev = RandomOrphan();

        CTransaction tx;
        tx.vin.resize(1);
        tx.vin[0].prevout.n = 0;
        tx.vin[0].prevout.hash = txPrev.GetHash();
        tx.vout.resize(1);
        tx.vout[0].nValue = 1*CENT;
        tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
        SignSignature(keystore, txPrev, tx, 0);

        CDataStream ds(SER_DISK, CLIENT_VERSION);
        ds << tx;
        AddOrphanTx(ds);
    }

    // This really-big orphan should be ignored:
    for (int i = 0; i < 10; i++)
    {
        CTransaction txPrev = RandomOrphan();

        CTransaction tx;
        tx.vout.resize(1);
        tx.vout[0].nValue = 1*CENT;
        tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
        tx.vin.resize(500);
        for (int j = 0; j < tx.vin.size(); j++)
        {
            tx.vin[j].prevout.n = j;
            tx.vin[j].prevout.hash = txPrev.GetHash();
        }
        SignSignature(keystore, txPrev, tx, 0);
        // Re-use same signature for other inputs
        // (they don't have to be valid for this test)
        for (int j = 1; j < tx.vin.size(); j++)
            tx.vin[j].scriptSig = tx.vin[0].scriptSig;

        CDataStream ds(SER_DISK, CLIENT_VERSION);
        ds << tx;
        BOOST_CHECK(!AddOrphanTx(ds));
    }

    // Test LimitOrphanTxSize() function:
    LimitOrphanTxSize(40);
    BOOST_CHECK(mapOrphanTransactions.size() <= 40);
    LimitOrphanTxSize(10);
    BOOST_CHECK(mapOrphanTransactions.size() <= 10);
    LimitOrphanTxSize(0);
    BOOST_CHECK(mapOrphanTransactions.empty());
    BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
}

BOOST_AUTO_TEST_CASE(DoS_checkSig)
{
    // Test signature caching code (see key.cpp Verify() methods)

    CKey key;
    key.MakeNewKey(true);
    CBasicKeyStore keystore;
    keystore.AddKey(key);

    // 100 orphan transactions:
    static const int NPREV=100;
    CTransaction orphans[NPREV];
    for (int i = 0; i < NPREV; i++)
    {
        CTransaction& tx = orphans[i];
        tx.vin.resize(1);
        tx.vin[0].prevout.n = 0;
        tx.vin[0].prevout.hash = GetRandHash();
        tx.vin[0].scriptSig << OP_1;
        tx.vout.resize(1);
        tx.vout[0].nValue = 1*CENT;
        tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());

        CDataStream ds(SER_DISK, CLIENT_VERSION);
        ds << tx;
        AddOrphanTx(ds);
    }

    // Create a transaction that depends on orphans:
    CTransaction tx;
    tx.vout.resize(1);
    tx.vout[0].nValue = 1*CENT;
    tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
    tx.vin.resize(NPREV);
    for (int j = 0; j < tx.vin.size(); j++)
    {
        tx.vin[j].prevout.n = 0;
        tx.vin[j].prevout.hash = orphans[j].GetHash();
    }
    // Creating signatures primes the cache:
    boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time();
    for (int j = 0; j < tx.vin.size(); j++)
        BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j));
    boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time();
    boost::posix_time::time_duration msdiff = mst2 - mst1;
    long nOneValidate = msdiff.total_milliseconds();
    if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate);

    // ... now validating repeatedly should be quick:
    // 2.8GHz machine, -g build: Sign takes ~760ms,
    // uncached Verify takes ~250ms, cached Verify takes ~50ms
    // (for 100 single-signature inputs)
    mst1 = boost::posix_time::microsec_clock::local_time();
    for (int i = 0; i < 5; i++)
        for (int j = 0; j < tx.vin.size(); j++)
            BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
    mst2 = boost::posix_time::microsec_clock::local_time();
    msdiff = mst2 - mst1;
    long nManyValidate = msdiff.total_milliseconds();
    if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate);

    BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");

    // Empty a signature, validation should fail:
    CScript save = tx.vin[0].scriptSig;
    tx.vin[0].scriptSig = CScript();
    BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
    tx.vin[0].scriptSig = save;

    // Swap signatures, validation should fail:
    std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
    BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
    BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL));
    std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);

    // Exercise -maxsigcachesize code:
    mapArgs["-maxsigcachesize"] = "10";
    // Generate a new, different signature for vin[0] to trigger cache clear:
    CScript oldSig = tx.vin[0].scriptSig;
    BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
    BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
    for (int j = 0; j < tx.vin.size(); j++)
        BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
    mapArgs.erase("-maxsigcachesize");

    LimitOrphanTxSize(0);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "base_test.hpp"

#include <algorithm>
#include <fstream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#include "../lib/storage/storage_manager.hpp"

namespace opossum {

void BaseTest::EXPECT_TABLE_EQ(const Table &tleft, const Table &tright, bool order_sensitive) {
  EXPECT_TRUE(_table_equal(tleft, tright, order_sensitive));
}

void BaseTest::ASSERT_TABLE_EQ(const Table &tleft, const Table &tright, bool order_sensitive) {
  ASSERT_TRUE(_table_equal(tleft, tright, order_sensitive));
}

void BaseTest::EXPECT_TABLE_EQ(std::shared_ptr<const Table> tleft, std::shared_ptr<const Table> tright,
                               bool order_sensitive) {
  EXPECT_TABLE_EQ(*tleft, *tright, order_sensitive);
}

void BaseTest::ASSERT_TABLE_EQ(std::shared_ptr<const Table> tleft, std::shared_ptr<const Table> tright,
                               bool order_sensitive) {
  ASSERT_TABLE_EQ(*tleft, *tright, order_sensitive);
}

BaseTest::Matrix BaseTest::_table_to_matrix(const Table &t) {
  // initialize matrix with table sizes
  Matrix matrix(t.row_count(), std::vector<AllTypeVariant>(t.col_count()));

  // set values
  unsigned row_offset = 0;
  for (ChunkID chunk_id = 0; chunk_id < t.chunk_count(); chunk_id++) {
    const Chunk &chunk = t.get_chunk(chunk_id);

    for (size_t col_id = 0; col_id < t.col_count(); ++col_id) {
      std::shared_ptr<BaseColumn> column = chunk.get_column(col_id);

      for (ChunkOffset chunk_offset = 0; chunk_offset < chunk.size(); ++chunk_offset) {
        matrix[row_offset + chunk_offset][col_id] = (*column)[chunk_offset];
      }
    }
    row_offset += chunk.size();
  }

  return matrix;
}

void BaseTest::_print_matrix(const BaseTest::Matrix &m) {
  std::cout << "-------------" << std::endl;
  for (unsigned row = 0; row < m.size(); row++) {
    for (unsigned col = 0; col < m[row].size(); col++) {
      std::cout << std::setw(8) << m[row][col] << " ";
    }
    std::cout << std::endl;
  }
  std::cout << "-------------" << std::endl;
}

::testing::AssertionResult BaseTest::_table_equal(const Table &tleft, const Table &tright, bool order_sensitive) {
  Matrix left = _table_to_matrix(tleft);
  Matrix right = _table_to_matrix(tright);
  // compare schema of tables
  //  - column count
  if (tleft.col_count() != tright.col_count()) {
    _print_matrix(left);
    _print_matrix(right);
    return ::testing::AssertionFailure() << "Number of columns is different.";
  }
  //  - column names and types
  for (size_t col_id = 0; col_id < tright.col_count(); ++col_id) {
    if (tleft.column_type(col_id) != tright.column_type(col_id) ||
        tleft.column_name(col_id) != tright.column_name(col_id)) {
      std::cout << "Column with ID " << col_id << " is different" << std::endl;
      std::cout << "Got: " << tleft.column_name(col_id) << " (" << tleft.column_type(col_id) << ")" << std::endl;
      std::cout << "Expected: " << tright.column_name(col_id) << " (" << tright.column_type(col_id) << ")" << std::endl;
      return ::testing::AssertionFailure() << "Table schema is different.";
    }
  }

  // compare content of tables
  //  - row count for fast failure
  if (tleft.row_count() != tright.row_count()) {
    _print_matrix(left);
    _print_matrix(right);
    return ::testing::AssertionFailure() << "Number of rows is different.";
  }

  // sort if order does not matter
  if (!order_sensitive) {
    std::sort(left.begin(), left.end());
    std::sort(right.begin(), right.end());
  }

  if (left == right) {
    return ::testing::AssertionSuccess();
  } else {
    _print_matrix(left);
    _print_matrix(right);
    return ::testing::AssertionFailure() << "Table content is different.";
  }
}

template <typename T>
std::vector<T> BaseTest::_split(const std::string &str, char delimiter) {
  std::vector<T> internal;
  std::stringstream ss(str);
  std::string tok;

  while (std::getline(ss, tok, delimiter)) {
    internal.push_back(tok);
  }

  return internal;
}

std::shared_ptr<Table> BaseTest::load_table(const std::string &file_name, size_t chunk_size) {
  std::shared_ptr<Table> test_table = std::make_shared<Table>(chunk_size);

  std::ifstream infile(file_name);
  std::string line;

  std::getline(infile, line);
  std::vector<std::string> col_names = _split<std::string>(line, '|');
  std::getline(infile, line);
  std::vector<std::string> col_types = _split<std::string>(line, '|');

  for (size_t i = 0; i < col_names.size(); i++) {
    test_table->add_column(col_names[i], col_types[i]);
  }

  while (std::getline(infile, line)) {
    std::vector<AllTypeVariant> values = _split<AllTypeVariant>(line, '|');
    test_table->append(values);
  }
  return test_table;
}

BaseTest::~BaseTest() { StorageManager::reset(); }

}  // namespace opossum
<commit_msg>Update base_test.cpp<commit_after>#include "base_test.hpp"

#include <algorithm>
#include <fstream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#include "../lib/storage/storage_manager.hpp"

namespace opossum {

void BaseTest::EXPECT_TABLE_EQ(const Table &tleft, const Table &tright, bool order_sensitive) {
  EXPECT_TRUE(_table_equal(tleft, tright, order_sensitive));
}

void BaseTest::ASSERT_TABLE_EQ(const Table &tleft, const Table &tright, bool order_sensitive) {
  ASSERT_TRUE(_table_equal(tleft, tright, order_sensitive));
}

void BaseTest::EXPECT_TABLE_EQ(std::shared_ptr<const Table> tleft, std::shared_ptr<const Table> tright,
                               bool order_sensitive) {
  EXPECT_TABLE_EQ(*tleft, *tright, order_sensitive);
}

void BaseTest::ASSERT_TABLE_EQ(std::shared_ptr<const Table> tleft, std::shared_ptr<const Table> tright,
                               bool order_sensitive) {
  ASSERT_TABLE_EQ(*tleft, *tright, order_sensitive);
}

BaseTest::Matrix BaseTest::_table_to_matrix(const Table &t) {
  // initialize matrix with table sizes
  Matrix matrix(t.row_count(), std::vector<AllTypeVariant>(t.col_count()));

  // set values
  unsigned row_offset = 0;
  for (ChunkID chunk_id = 0; chunk_id < t.chunk_count(); chunk_id++) {
    const Chunk &chunk = t.get_chunk(chunk_id);

    for (size_t col_id = 0; col_id < t.col_count(); ++col_id) {
      std::shared_ptr<BaseColumn> column = chunk.get_column(col_id);

      for (ChunkOffset chunk_offset = 0; chunk_offset < chunk.size(); ++chunk_offset) {
        matrix[row_offset + chunk_offset][col_id] = (*column)[chunk_offset];
      }
    }
    row_offset += chunk.size();
  }

  return matrix;
}

void BaseTest::_print_matrix(const BaseTest::Matrix &m) {
  std::cout << "-------------" << std::endl;
  for (unsigned row = 0; row < m.size(); row++) {
    for (unsigned col = 0; col < m[row].size(); col++) {
      std::cout << std::setw(8) << m[row][col] << " ";
    }
    std::cout << std::endl;
  }
  std::cout << "-------------" << std::endl;
}

::testing::AssertionResult BaseTest::_table_equal(const Table &tleft, const Table &tright, bool order_sensitive) {
  Matrix left = _table_to_matrix(tleft);
  Matrix right = _table_to_matrix(tright);
  // compare schema of tables
  //  - column count
  if (tleft.col_count() != tright.col_count()) {
    _print_matrix(left);
    _print_matrix(right);
    return ::testing::AssertionFailure() << "Number of columns is different.";
  }
  //  - column names and types
  for (size_t col_id = 0; col_id < tright.col_count(); ++col_id) {
    if (tleft.column_type(col_id) != tright.column_type(col_id) ||
        tleft.column_name(col_id) != tright.column_name(col_id)) {
      std::cout << "Column with ID " << col_id << " is different" << std::endl;
      std::cout << "Got: " << tleft.column_name(col_id) << " (" << tleft.column_type(col_id) << ")" << std::endl;
      std::cout << "Expected: " << tright.column_name(col_id) << " (" << tright.column_type(col_id) << ")" << std::endl;
      return ::testing::AssertionFailure() << "Table schema is different.";
    }
  }

  // compare content of tables
  //  - row count for fast failure
  if (tleft.row_count() != tright.row_count()) {
    _print_matrix(left);
    _print_matrix(right);
    return ::testing::AssertionFailure() << "Number of rows is different.";
  }

  // sort if order does not matter
  if (!order_sensitive) {
    std::sort(left.begin(), left.end());
    std::sort(right.begin(), right.end());
  }

  for (unsigned row = 0; row < left.size(); row++)
    for (unsigned col = 0; col < left[row].size(); col++) {
      if (tleft.column_type(col) == "float") {
        EXPECT_FLOAT_EQ(type_cast<float>(left[row][col]), type_cast<float>(right[row][col])) << "Row/Col:" << row << "/"
                                                                                << col;
      } else if (tleft.column_type(col) == "double") {
        EXPECT_DOUBLE_EQ(type_cast<double>(left[row][col]), type_cast<double>(right[row][col])) << "Row/Col:" << row
                                                                                << "/" << col;
      } else {
        EXPECT_EQ(left[row][col], right[row][col]) << "Row:" << row + 1 << " Col:" << col + 1;
      }
    }

  return ::testing::AssertionSuccess();
}

template <typename T>
std::vector<T> BaseTest::_split(const std::string &str, char delimiter) {
  std::vector<T> internal;
  std::stringstream ss(str);
  std::string tok;

  while (std::getline(ss, tok, delimiter)) {
    internal.push_back(tok);
  }

  return internal;
}

std::shared_ptr<Table> BaseTest::load_table(const std::string &file_name, size_t chunk_size) {
  std::shared_ptr<Table> test_table = std::make_shared<Table>(chunk_size);

  std::ifstream infile(file_name);
  std::string line;

  std::getline(infile, line);
  std::vector<std::string> col_names = _split<std::string>(line, '|');
  std::getline(infile, line);
  std::vector<std::string> col_types = _split<std::string>(line, '|');

  for (size_t i = 0; i < col_names.size(); i++) {
    test_table->add_column(col_names[i], col_types[i]);
  }

  while (std::getline(infile, line)) {
    std::vector<AllTypeVariant> values = _split<AllTypeVariant>(line, '|');
    test_table->append(values);
  }
  return test_table;
}

BaseTest::~BaseTest() { StorageManager::reset(); }

}  // namespace opossum
<|endoftext|>


<commit_before>#pragma once

#include <gtest/gtest.h>
#include <parser/BibParser.h>

TEST(BibParserTest, simple)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{LibroA}{book}{\n"
										  "  author={Albiac, F.},\n"
										  "  author={Kalton, N.J.},\n"
										  "  title={Topics in Banach spaces theory},\n"
										  "  series={Grad. Text in Math.},\n"
										  "  volume={233},\n"
										  "  publisher={Springer},\n"
										  "  date={2006},\n"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("LibroA", bib.getCite());
	EXPECT_EQ("book", bib.getEntryType());
	EXPECT_EQ("Albiac, F.", bib.getValue("author"));
	EXPECT_EQ("Kalton, N.J.", bib.getValue("author", 1));
	EXPECT_EQ("Grad. Text in Math.", bib.getValue("series"));
	EXPECT_EQ("233", bib.getValue("volume"));
	EXPECT_EQ("Springer", bib.getValue("publisher"));
	EXPECT_EQ("2006", bib.getValue("date"));
	EXPECT_EQ("Topics in Banach spaces theory", bib.getValue("title"));
}

TEST(BibParserTest, notFormated)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{LibroA}{book}{"
										  "author={Albiac, F.},"
										  "author={Kalton, N.J.},"
										  "title={Topics in Banach spaces theory},"
										  "series={Grad. Text in Math.},"
										  "volume={233},"
										  "publisher={Springer},"
										  "date={2006},"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("LibroA", bib.getCite());
	EXPECT_EQ("book", bib.getEntryType());
	EXPECT_EQ("Albiac, F.", bib.getValue("author"));
	EXPECT_EQ("Kalton, N.J.", bib.getValue("author", 1));
	EXPECT_EQ("Grad. Text in Math.", bib.getValue("series"));
	EXPECT_EQ("233", bib.getValue("volume"));
	EXPECT_EQ("Springer", bib.getValue("publisher"));
	EXPECT_EQ("2006", bib.getValue("date"));
}

TEST(BibParserTest, extraSpaces)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib  {LibroA}   {book}    {"
										  "    author={Albiac, F.}   ,   "
										  "   author={Kalton, N.J.} ,   "
										  "  title={Topics in Banach spaces theory}         ,            "
										  " series={Grad. Text in Math.} , "
										  "             volume={233},       "
										  "       publisher={Springer}           ,"
										  "      date={2006}    ,     "
										  "           }");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("LibroA", bib.getCite());
	EXPECT_EQ("book", bib.getEntryType());
	EXPECT_EQ("Albiac, F.", bib.getValue("author"));
	EXPECT_EQ("Kalton, N.J.", bib.getValue("author", 1));
	EXPECT_EQ("Grad. Text in Math.", bib.getValue("series"));
	EXPECT_EQ("233", bib.getValue("volume"));
	EXPECT_EQ("Springer", bib.getValue("publisher"));
	EXPECT_EQ("2006", bib.getValue("date"));
}

TEST(BibParserTest, minimalKeys)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{A}{B}{"
										  "a={Albiac, F.},"
										  "a={Kalton, N.J.},"
										  "t={Topics in Banach spaces theory},"
										  "s={Grad. Text in Math.},"
										  "v={233},"
										  "p={Springer},"
										  "d={2006},"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("A", bib.getCite());
	EXPECT_EQ("B", bib.getEntryType());
	EXPECT_EQ("Topics in Banach spaces theory", bib.getValue("t"));
	EXPECT_EQ("Albiac, F.", bib.getValue("a"));
	EXPECT_EQ("Kalton, N.J.", bib.getValue("a", 1));
	EXPECT_EQ("Grad. Text in Math.", bib.getValue("s"));
	EXPECT_EQ("233", bib.getValue("v"));
	EXPECT_EQ("Springer", bib.getValue("p"));
	EXPECT_EQ("2006", bib.getValue("d"));
}

TEST(BibParserTest, minimalKeysAndValues)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{A}{B}{"
										  "a={a},"
										  "a={b},"
										  "t={c},"
										  "s={d},"
										  "v={e},"
										  "p={f},"
										  "d={{}},"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("A", bib.getCite());
	EXPECT_EQ("B", bib.getEntryType());
	EXPECT_EQ("c", bib.getValue("t"));
	EXPECT_EQ("a", bib.getValue("a"));
	EXPECT_EQ("b", bib.getValue("a", 1));
	EXPECT_EQ("d", bib.getValue("s"));
	EXPECT_EQ("e", bib.getValue("v"));
	EXPECT_EQ("f", bib.getValue("p"));
	EXPECT_EQ("{}", bib.getValue("d"));
}

TEST(BibParserTest, minimalKeysAndValuesRandomSpaces)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib  {A} {B}  {"
										  "a={a}  ,"
										  "             a={b}  ,"
										  "   t={c} , "
										  "  s={d},   "
										  "       v={e},"
										  "p={f}  ,"
										  "d={{  }  },"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("A", bib.getCite());
	EXPECT_EQ("B", bib.getEntryType());
	EXPECT_EQ("c", bib.getValue("t"));
	EXPECT_EQ("a", bib.getValue("a"));
	EXPECT_EQ("b", bib.getValue("a", 1));
	EXPECT_EQ("d", bib.getValue("s"));
	EXPECT_EQ("e", bib.getValue("v"));
	EXPECT_EQ("f", bib.getValue("p"));
	EXPECT_EQ("{  }  ", bib.getValue("d"));
}

<commit_msg>Add more tests<commit_after>#pragma once

#include <gtest/gtest.h>
#include <parser/BibParser.h>

TEST(BibParserTest, simple)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{LibroA}{book}{\n"
										  "  author={Albiac, F.},\n"
										  "  author={Kalton, N.J.},\n"
										  "  title={Topics in Banach spaces theory},\n"
										  "  series={Grad. Text in Math.},\n"
										  "  volume={233},\n"
										  "  publisher={Springer},\n"
										  "  date={2006},\n"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("LibroA", bib.getCite());
	EXPECT_EQ("book", bib.getEntryType());
	EXPECT_EQ("Albiac, F.", bib.getValue("author"));
	EXPECT_EQ("Kalton, N.J.", bib.getValue("author", 1));
	EXPECT_EQ("Grad. Text in Math.", bib.getValue("series"));
	EXPECT_EQ("233", bib.getValue("volume"));
	EXPECT_EQ("Springer", bib.getValue("publisher"));
	EXPECT_EQ("2006", bib.getValue("date"));
	EXPECT_EQ("Topics in Banach spaces theory", bib.getValue("title"));
}

TEST(BibParserTest, notFormated)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{LibroA}{book}{"
										  "author={Albiac, F.},"
										  "author={Kalton, N.J.},"
										  "title={Topics in Banach spaces theory},"
										  "series={Grad. Text in Math.},"
										  "volume={233},"
										  "publisher={Springer},"
										  "date={2006},"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("LibroA", bib.getCite());
	EXPECT_EQ("book", bib.getEntryType());
	EXPECT_EQ("Albiac, F.", bib.getValue("author"));
	EXPECT_EQ("Kalton, N.J.", bib.getValue("author", 1));
	EXPECT_EQ("Grad. Text in Math.", bib.getValue("series"));
	EXPECT_EQ("233", bib.getValue("volume"));
	EXPECT_EQ("Springer", bib.getValue("publisher"));
	EXPECT_EQ("2006", bib.getValue("date"));
}

TEST(BibParserTest, extraSpaces)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib  {LibroA}   {book}    {"
										  "    author={Albiac, F.}   ,   "
										  "   author={Kalton, N.J.} ,   "
										  "  title={Topics in Banach spaces theory}         ,            "
										  " series={Grad. Text in Math.} , "
										  "             volume={233},       "
										  "       publisher={Springer}           ,"
										  "      date={2006}    ,     "
										  "           }");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("LibroA", bib.getCite());
	EXPECT_EQ("book", bib.getEntryType());
	EXPECT_EQ("Albiac, F.", bib.getValue("author"));
	EXPECT_EQ("Kalton, N.J.", bib.getValue("author", 1));
	EXPECT_EQ("Grad. Text in Math.", bib.getValue("series"));
	EXPECT_EQ("233", bib.getValue("volume"));
	EXPECT_EQ("Springer", bib.getValue("publisher"));
	EXPECT_EQ("2006", bib.getValue("date"));
}

TEST(BibParserTest, minimalKeys)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{A}{B}{"
										  "a={Albiac, F.},"
										  "a={Kalton, N.J.},"
										  "t={Topics in Banach spaces theory},"
										  "s={Grad. Text in Math.},"
										  "v={233},"
										  "p={Springer},"
										  "d={2006},"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("A", bib.getCite());
	EXPECT_EQ("B", bib.getEntryType());
	EXPECT_EQ("Topics in Banach spaces theory", bib.getValue("t"));
	EXPECT_EQ("Albiac, F.", bib.getValue("a"));
	EXPECT_EQ("Kalton, N.J.", bib.getValue("a", 1));
	EXPECT_EQ("Grad. Text in Math.", bib.getValue("s"));
	EXPECT_EQ("233", bib.getValue("v"));
	EXPECT_EQ("Springer", bib.getValue("p"));
	EXPECT_EQ("2006", bib.getValue("d"));
}

TEST(BibParserTest, minimalKeysAndValues)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{A}{B}{"
										  "a={a},"
										  "a={b},"
										  "t={c},"
										  "s={d},"
										  "v={e},"
										  "p={f},"
										  "d={{}},"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("A", bib.getCite());
	EXPECT_EQ("B", bib.getEntryType());
	EXPECT_EQ("c", bib.getValue("t"));
	EXPECT_EQ("a", bib.getValue("a"));
	EXPECT_EQ("b", bib.getValue("a", 1));
	EXPECT_EQ("d", bib.getValue("s"));
	EXPECT_EQ("e", bib.getValue("v"));
	EXPECT_EQ("f", bib.getValue("p"));
	EXPECT_EQ("{}", bib.getValue("d"));
}

TEST(BibParserTest, minimalKeysAndValuesRandomSpaces)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib  {A} {B}  {"
										  "a={a}  ,"
										  "             a={b}  ,"
										  "   t={c} , "
										  "  s={d},   "
										  "       v={e},"
										  "p={f}  ,"
										  "d={{  }  },"
										  "}");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("A", bib.getCite());
	EXPECT_EQ("B", bib.getEntryType());
	EXPECT_EQ("c", bib.getValue("t"));
	EXPECT_EQ("a", bib.getValue("a"));
	EXPECT_EQ("b", bib.getValue("a", 1));
	EXPECT_EQ("d", bib.getValue("s"));
	EXPECT_EQ("e", bib.getValue("v"));
	EXPECT_EQ("f", bib.getValue("p"));
	EXPECT_EQ("{  }  ", bib.getValue("d"));
}

TEST(BibParserTest, nested)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{KostrikinS1965}{article}{ author={Kostrikin, A. I.}, "
										  "author={\\v{S}afarevi\\v{c}, I. R.}, title={Cartan pseudogroups and Lie "
										  "$p$-algebras}, journal={Dokl. Akad. Nauk SSSR}, volume={168}, date={1965},"
										  " pages={740--742}, translation={ journal={Soviet Math. Dokl.}, volume={6}, date={1965}, pages={715--718} }, review={\\MR{0199235}} }");

	EXPECT_EQ(1, singleBib.size());

	auto& bib = singleBib.front();
	EXPECT_EQ("KostrikinS1965", bib.getCite());
	EXPECT_EQ("article", bib.getEntryType());
	EXPECT_EQ("Kostrikin, A. I.", bib.getValue("author"));
	EXPECT_EQ("\\v{S}afarevi\\v{c}, I. R.", bib.getValue("author", 1));
	EXPECT_EQ("168", bib.getValue("volume"));
	EXPECT_EQ("1965", bib.getValue("date"));
	EXPECT_EQ("740--742", bib.getValue("pages"));
	EXPECT_EQ("\\MR{0199235}", bib.getValue("review"));
	EXPECT_EQ(" journal={Soviet Math. Dokl.}, volume={6}, date={1965}, pages={715--718} ", bib.getValue("translation"));
	//TODO check parsing nested
	EXPECT_EQ("Dokl. Akad. Nauk SSSR", bib.getValue("journal"));
	EXPECT_EQ("Cartan pseudogroups and Lie $p$-algebras", bib.getValue("title"));
}

TEST(BibParserTest, two)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{LibroA}{book}{\n"
										  "  author={Albiac, F.},\n"
										  "  author={Kalton, N.J.},\n"
										  "  title={Topics in Banach spaces theory},\n"
										  "  series={Grad. Text in Math.},\n"
										  "  volume={233},\n"
										  "  publisher={Springer},\n"
										  "  date={2006},\n"
										  "}\n"
										  "\\bib{LibroCa}{book}{\n"
										  "  author={Carothers, N.},\n"
										  "  title={A~short course on Banach spaces theory},\n"
										  "  series={London Math. Soc student text},\n"
										  "  volume={64},\n"
										  "  publisher={Cambridge Univ. Press},\n"
										  "  date={2004},\n"
										  "}");

	EXPECT_EQ(2, singleBib.size());
	{
		auto& bib = singleBib[0];
		EXPECT_EQ("LibroA", bib.getCite());
		EXPECT_EQ("book", bib.getEntryType());
		EXPECT_EQ("Albiac, F.", bib.getValue("author"));
		EXPECT_EQ("Kalton, N.J.", bib.getValue("author", 1));
		EXPECT_EQ("233", bib.getValue("volume"));
		EXPECT_EQ("2006", bib.getValue("date"));
		EXPECT_EQ("Grad. Text in Math.", bib.getValue("series"));
		EXPECT_EQ("Springer", bib.getValue("publisher"));
		EXPECT_EQ("Topics in Banach spaces theory", bib.getValue("title"));
	}
	{
		auto& bib = singleBib[1];
		EXPECT_EQ("LibroCa", bib.getCite());
		EXPECT_EQ("book", bib.getEntryType());
		EXPECT_EQ("Carothers, N.", bib.getValue("author"));
		EXPECT_EQ("A~short course on Banach spaces theory", bib.getValue("title"));
		EXPECT_EQ("London Math. Soc student text", bib.getValue("series"));
		EXPECT_EQ("64", bib.getValue("volume"));
		EXPECT_EQ("Cambridge Univ. Press", bib.getValue("publisher"));
		EXPECT_EQ("2004", bib.getValue("date"));
	}
}

TEST(BibParserTest, three)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{LibroA}{book}{\n"
										  "  author={Albiac, F.},\n"
										  "  author={Kalton, N.J.},\n"
										  "  title={Topics in Banach spaces theory},\n"
										  "  series={Grad. Text in Math.},\n"
										  "  volume={233},\n"
										  "  publisher={Springer},\n"
										  "  date={2006},\n"
										  "}\n"
										  "\\bib{LibroCa}{book}{\n"
										  "  author={Carothers, N.},\n"
										  "  title={A~short course on Banach spaces theory},\n"
										  "  series={London Math. Soc student text},\n"
										  "  volume={64},\n"
										  "  publisher={Cambridge Univ. Press},\n"
										  "  date={2004},\n"
										  "}\n"
										  "\\bib{LibroC}{book}{\n"
										  "  author={Cruz-Uribe, D.},\n"
										  "  author={Fiorenza, A.},\n"
										  "  title={Variable Lebesgue spaces. Foundations and harmonic analysis},\n"
										  "  series={Applied and Numerical Harmonic Analysis},\n"
										  "  publisher={Birkhauser/Springer},\n"
										  "  place={Heidelberg.},\n"
										  "  date={2013},\n"
										  "}");

	EXPECT_EQ(3, singleBib.size());
	{
		auto& bib = singleBib[0];
		EXPECT_EQ("LibroA", bib.getCite());
		EXPECT_EQ("book", bib.getEntryType());
		EXPECT_EQ("Albiac, F.", bib.getValue("author"));
		EXPECT_EQ("Kalton, N.J.", bib.getValue("author", 1));
		EXPECT_EQ("233", bib.getValue("volume"));
		EXPECT_EQ("2006", bib.getValue("date"));
		EXPECT_EQ("Grad. Text in Math.", bib.getValue("series"));
		EXPECT_EQ("Springer", bib.getValue("publisher"));
		EXPECT_EQ("Topics in Banach spaces theory", bib.getValue("title"));
	}
	{
		auto& bib = singleBib[1];
		EXPECT_EQ("LibroCa", bib.getCite());
		EXPECT_EQ("book", bib.getEntryType());
		EXPECT_EQ("Carothers, N.", bib.getValue("author"));
		EXPECT_EQ("A~short course on Banach spaces theory", bib.getValue("title"));
		EXPECT_EQ("London Math. Soc student text", bib.getValue("series"));
		EXPECT_EQ("64", bib.getValue("volume"));
		EXPECT_EQ("Cambridge Univ. Press", bib.getValue("publisher"));
		EXPECT_EQ("2004", bib.getValue("date"));
	}
	{
		auto& bib = singleBib[2];
		EXPECT_EQ("LibroC", bib.getCite());
		EXPECT_EQ("book", bib.getEntryType());
		EXPECT_EQ("Cruz-Uribe, D.", bib.getValue("author"));
		EXPECT_EQ("Fiorenza, A.", bib.getValue("author", 1));
		EXPECT_EQ("Variable Lebesgue spaces. Foundations and harmonic analysis", bib.getValue("title"));
		EXPECT_EQ("Applied and Numerical Harmonic Analysis", bib.getValue("series"));
		EXPECT_EQ("Heidelberg.", bib.getValue("place"));
		EXPECT_EQ("Birkhauser/Springer", bib.getValue("publisher"));
		EXPECT_EQ("2013", bib.getValue("date"));
	}
}

TEST(BibParserTest, threeMinimalFormat)
{
	BibParser parser;

	auto singleBib = parser.parse("\\bib{LibroA}{book}{"
										  "author={Albiac, F.},"
										  "author={Kalton, N.J.},"
										  "title={Topics in Banach spaces theory},"
										  "series={Grad. Text in Math.},"
										  "volume={233},"
										  "publisher={Springer},"
										  "date={2006},"
										  "}"
										  "\\bib{LibroCa}{book}{"
										  "author={Carothers, N.},"
										  "title={A~short course on Banach spaces theory},"
										  "series={London Math. Soc student text},"
										  "volume={64},"
										  "publisher={Cambridge Univ. Press},"
										  "date={2004},"
										  "}"
										  "\\bib{LibroC}{book}{"
										  "author={Cruz-Uribe, D.},"
										  "author={Fiorenza, A.},"
										  "title={Variable Lebesgue spaces. Foundations and harmonic analysis},"
										  "series={Applied and Numerical Harmonic Analysis},"
										  "publisher={Birkhauser/Springer},"
										  "place={Heidelberg.},"
										  "date={2013},"
										  "}");

	EXPECT_EQ(3, singleBib.size());
	{
		auto& bib = singleBib[0];
		EXPECT_EQ("LibroA", bib.getCite());
		EXPECT_EQ("book", bib.getEntryType());
		EXPECT_EQ("Albiac, F.", bib.getValue("author"));
		EXPECT_EQ("Kalton, N.J.", bib.getValue("author", 1));
		EXPECT_EQ("233", bib.getValue("volume"));
		EXPECT_EQ("2006", bib.getValue("date"));
		EXPECT_EQ("Grad. Text in Math.", bib.getValue("series"));
		EXPECT_EQ("Springer", bib.getValue("publisher"));
		EXPECT_EQ("Topics in Banach spaces theory", bib.getValue("title"));
	}
	{
		auto& bib = singleBib[1];
		EXPECT_EQ("LibroCa", bib.getCite());
		EXPECT_EQ("book", bib.getEntryType());
		EXPECT_EQ("Carothers, N.", bib.getValue("author"));
		EXPECT_EQ("A~short course on Banach spaces theory", bib.getValue("title"));
		EXPECT_EQ("London Math. Soc student text", bib.getValue("series"));
		EXPECT_EQ("64", bib.getValue("volume"));
		EXPECT_EQ("Cambridge Univ. Press", bib.getValue("publisher"));
		EXPECT_EQ("2004", bib.getValue("date"));
	}
	{
		auto& bib = singleBib[2];
		EXPECT_EQ("LibroC", bib.getCite());
		EXPECT_EQ("book", bib.getEntryType());
		EXPECT_EQ("Cruz-Uribe, D.", bib.getValue("author"));
		EXPECT_EQ("Fiorenza, A.", bib.getValue("author", 1));
		EXPECT_EQ("Variable Lebesgue spaces. Foundations and harmonic analysis", bib.getValue("title"));
		EXPECT_EQ("Applied and Numerical Harmonic Analysis", bib.getValue("series"));
		EXPECT_EQ("Heidelberg.", bib.getValue("place"));
		EXPECT_EQ("Birkhauser/Springer", bib.getValue("publisher"));
		EXPECT_EQ("2013", bib.getValue("date"));
	}
}
<|endoftext|>


<commit_before>#include <gmock/gmock.h>

#include <string>
#include <vector>

#include "mutant/IniParser.h"
#include "mutant/error.h"

class IniParserTest: public ::testing::Test {
public:
    Config config;
    IniParser parser;
};

TEST_F(IniParserTest, parse) {
  std::string content = R"(
[core]
user.email = test@example.com
path = /usr/local/lib/mutant/libs:$HOME/projects/mutant-libs
foo = "Some path with spaces here"

[watch]
bar = 12.3
)";

  int error = parser.parse(config, content);

  ASSERT_EQ(ERROR_OK, error);
  ASSERT_EQ(2, config.groups.size());

  auto it = config.groups.find("core");
  ASSERT_TRUE(it != config.groups.end());

  ConfigGroup& core = it->second;
  ASSERT_EQ(3, core.settings.size());

  auto emailIt = core.settings.find("user.email");
  ASSERT_TRUE(emailIt != core.settings.end());
  ASSERT_EQ("test@example.com", emailIt->second);

  auto pathIt = core.settings.find("path");
  ASSERT_TRUE(pathIt != core.settings.end());
  ASSERT_EQ("/usr/local/lib/mutant/libs:$HOME/projects/mutant-libs", pathIt->second);

  auto fooIt = core.settings.find("foo");
  ASSERT_TRUE(fooIt != core.settings.end());
  ASSERT_EQ("Some path with spaces here", fooIt->second);

  auto watchIt = config.groups.find("watch");
  ASSERT_TRUE(watchIt != config.groups.end());

  ConfigGroup& watch = watchIt->second;
  ASSERT_EQ(1, watch.settings.size());
}

TEST_F(IniParserTest, extractGroupName) {
  std::string content = " [some-group] ";
  std::string expected = "some-group";

  std::string name = IniParser::extractGroupName(content, 0, content.length());

  ASSERT_EQ(expected, name);
}
<commit_msg>remove IniParserTest::extractGroupName<commit_after>#include <gmock/gmock.h>

#include <string>
#include <vector>

#include "mutant/IniParser.h"
#include "mutant/error.h"

class IniParserTest: public ::testing::Test {
public:
    Config config;
    IniParser parser;
};

TEST_F(IniParserTest, parse) {
  std::string content = R"(
[core]
user.email = test@example.com
path = /usr/local/lib/mutant/libs:$HOME/projects/mutant-libs
foo = "Some path with spaces here"

[watch]
bar = 12.3
)";

  int error = parser.parse(config, content);

  ASSERT_EQ(ERROR_OK, error);
  ASSERT_EQ(2, config.groups.size());

  auto it = config.groups.find("core");
  ASSERT_TRUE(it != config.groups.end());

  ConfigGroup& core = it->second;
  ASSERT_EQ(3, core.settings.size());

  auto emailIt = core.settings.find("user.email");
  ASSERT_TRUE(emailIt != core.settings.end());
  ASSERT_EQ("test@example.com", emailIt->second);

  auto pathIt = core.settings.find("path");
  ASSERT_TRUE(pathIt != core.settings.end());
  ASSERT_EQ("/usr/local/lib/mutant/libs:$HOME/projects/mutant-libs", pathIt->second);

  auto fooIt = core.settings.find("foo");
  ASSERT_TRUE(fooIt != core.settings.end());
  ASSERT_EQ("Some path with spaces here", fooIt->second);

  auto watchIt = config.groups.find("watch");
  ASSERT_TRUE(watchIt != config.groups.end());

  ConfigGroup& watch = watchIt->second;
  ASSERT_EQ(1, watch.settings.size());
}
<|endoftext|>


<commit_before>/* flappy.cc --- ncurses flappy bird clone
 * This is free and unencumbered software released into the public domain.
 * c++ -std=c++11 flappy.cc -lncurses -lm -o flappy
 */

#include <algorithm>
#include <thread>
#include <deque>
#include <ctime>
#include <cmath>
#include <cstring>
#include <ncurses.h>
#include "sqlite3.h"
#include "highscores.hh"

struct Display {
  Display(int width = 40, int height = 20) : height{height}, width{width} {
    initscr();
    raw();
    timeout(0);
    noecho();
    curs_set(0);
    keypad(stdscr, TRUE);
    erase();
  }

  ~Display() { endwin(); }

  void erase() {
    ::erase();
    for (int y = 0; y < height; y++) {
      mvaddch(y, 0, '|');
      mvaddch(y, width - 1, '|');
    }
    for (int x = 0; x < width; x++) {
      mvaddch(0, x, '-');
      mvaddch(height - 1, x, '-');
    }
    mvaddch(0, 0, '/');
    mvaddch(height - 1, 0, '\\');
    mvaddch(0, width - 1, '\\');
    mvaddch(height - 1, width - 1, '/');
  }

  void refresh() { ::refresh(); }

  const int height, width;

  int block_getch() {
    refresh();
    timeout(-1);
    int c = getch();
    timeout(0);
    return c;
  }

  void read_name(int y, int x, char *target, size_t n) {
    int p = 0;
    timeout(-1);
    curs_set(1);
    bool reading = true;
    while (reading) {
      move(y, x + p);
      refresh();
      int c = getch();
      switch (c) {
        case KEY_ENTER:
        case '\n':
        case '\r':
          reading = false;
          break;
        case KEY_LEFT:
        case KEY_BACKSPACE:
          if (p > 0) mvaddch(y, x + --p, ' ');
          break;
        default:
          if (p < n - 1) {
            target[p] = c;
            mvaddch(y, x + p++, c);
          }
      }
    }
    target[p + 1] = '\0';
    timeout(0);
    curs_set(0);
  }
};

struct World {
  World(Display *display) : display{display} {
    for (int x = 1; x < display->width - 1; x++) {
      walls.push_back(0);
    }
  }

  std::deque<int> walls;
  Display *display;
  int steps = 0;

  constexpr static int kRate = 2, kVGap = 2, kHGap = 10;

  int rand_wall() {
    int h = display->height;
    return (rand() % h / 2) + h / 4;
  }

  void step() {
    steps++;
    if (steps % kRate == 0) {
      walls.pop_front();
      switch (steps % (kRate * kHGap)) {
        case 0:
          walls.push_back(rand_wall());
          break;
        case kRate * 1:
        case kRate * 2:
          walls.push_back(walls.back());
          break;
        default:
          walls.push_back(0);
      }
    }
  }

  void draw() {
    for (int i = 0; i < walls.size(); i++) {
      int wall = walls[i];
      if (wall != 0) {
        for (int y = 1; y < display->height - 1; y++) {
          if (y == wall - kVGap - 1|| y == wall + kVGap + 1) {
            mvaddch(y, i + 1, '=');
          } else if (y < wall - kVGap || y > wall + kVGap) {
            mvaddch(y, i + 1, '*');
          }
        }
      }
    }
    mvprintw(display->height, 0, "Score: %d", score());
  }

  int score() { return std::max(0, steps / (kRate * kHGap) - 2); }
};

struct Bird {
  Bird(Display *display) : y{display->height / 2.0}, display{display} {}

  static constexpr double kImpulse = -0.8, kGravity = 0.1;

  double y, dy = kImpulse;
  Display *display;

  void gravity() {
    dy += kGravity;
    y += dy;
  }

  void poke() { dy = kImpulse; }

  void draw() { draw('@'); }

  void draw(int c) {
    int h = std::round(y);
    h = std::max(1, std::min(h, display->height - 2));
    mvaddch(h, display->width / 2, c);
  }

  bool is_alive(World &world) {
    if (y <= 0 || y >= display->height) {
      return false;
    }
    int wall = world.walls[display->width / 2 - 1];
    if (wall != 0) {
      return y > wall - World::kVGap && y < wall + World::kVGap;
    }
    return true;
  }
};

struct Game {
  Game(Display *display) : display{display}, bird{display}, world{display} {}

  Display *display;
  Bird bird;
  World world;

  int run() {
    display->erase();
    const char *intro = "[Press SPACE to hop upwards]";
    mvprintw(display->height / 2 - 2,
             display->width / 2 - std::strlen(intro) / 2, intro);
    bird.draw();
    display->block_getch();
    while (bird.is_alive(world)) {
      int c = getch();
      if (c == 'q') {
        return -1;
      } else if (c != ERR) {
        while (getch() != ERR)
          ;  // clear repeat buffer
        bird.poke();
      }
      display->erase();
      world.step();
      world.draw();
      bird.gravity();
      bird.draw();
      display->refresh();
      std::this_thread::sleep_for(std::chrono::milliseconds{67});
    }
    bird.draw('X');
    display->refresh();
    return world.score();
  }
};

void print_scores(Display &display, HighScores &scores) {
  mvprintw(0, display.width + 4, "== High Scores ==");
  int i = 1;
  for (auto &line : scores.top_scores()) {
    mvprintw(i, display.width + 1, "%s", line.name.c_str());
    clrtoeol();
    mvprintw(i, display.width + 24, "%d", line.score);
    i++;
  }
}

int main(int argc, const char **argv) {
  srand(std::time(NULL));
  const char *filename = "/tmp/flappy-scores.db";
  if (argc > 1) {
    filename = argv[1];
  }
  Display display;
  HighScores scores{filename, display.height};

  while (true) {
    Game game{&display};

    int score = game.run();
    if (score < 0) {
      return 0;  // game quit early
    }

    /* Game over */
    mvprintw(display.height + 1, 0, "Game over!");
    print_scores(display, scores);

    /* Enter new high score */
    if (scores.is_best(score)) {
      mvprintw(display.height + 2, 0, "You have a high score!");
      mvprintw(display.height + 3, 0, "Enter name: ");
      char name[23] = {0};
      display.read_name(display.height + 3, 12, name, sizeof(name));
      if (std::strlen(name) == 0) {
        std::strcpy(name, "(anonymous)");
      }
      scores.insert_score(name, score);
      move(display.height + 3, 0);
      clrtoeol();
      print_scores(display, scores);
    }

    /* Handle quit/restart */
    mvprintw(display.height + 2, 0, "Press 'q' to quit, 'r' to retry.");
    int c;
    while ((c = display.block_getch()) != 'r') {
      if (c == 'q' || c == ERR) {
        return 0;
      }
    }
  }
  return 0;
}
<commit_msg>Adjust score keeping.<commit_after>/* flappy.cc --- ncurses flappy bird clone
 * This is free and unencumbered software released into the public domain.
 * c++ -std=c++11 flappy.cc -lncurses -lm -o flappy
 */

#include <algorithm>
#include <thread>
#include <deque>
#include <ctime>
#include <cmath>
#include <cstring>
#include <ncurses.h>
#include "sqlite3.h"
#include "highscores.hh"

struct Display {
  Display(int width = 40, int height = 20) : height{height}, width{width} {
    initscr();
    raw();
    timeout(0);
    noecho();
    curs_set(0);
    keypad(stdscr, TRUE);
    erase();
  }

  ~Display() { endwin(); }

  void erase() {
    ::erase();
    for (int y = 0; y < height; y++) {
      mvaddch(y, 0, '|');
      mvaddch(y, width - 1, '|');
    }
    for (int x = 0; x < width; x++) {
      mvaddch(0, x, '-');
      mvaddch(height - 1, x, '-');
    }
    mvaddch(0, 0, '/');
    mvaddch(height - 1, 0, '\\');
    mvaddch(0, width - 1, '\\');
    mvaddch(height - 1, width - 1, '/');
  }

  void refresh() { ::refresh(); }

  const int height, width;

  int block_getch() {
    refresh();
    timeout(-1);
    int c = getch();
    timeout(0);
    return c;
  }

  void read_name(int y, int x, char *target, size_t n) {
    int p = 0;
    timeout(-1);
    curs_set(1);
    bool reading = true;
    while (reading) {
      move(y, x + p);
      refresh();
      int c = getch();
      switch (c) {
        case KEY_ENTER:
        case '\n':
        case '\r':
          reading = false;
          break;
        case KEY_LEFT:
        case KEY_BACKSPACE:
          if (p > 0) mvaddch(y, x + --p, ' ');
          break;
        default:
          if (p < n - 1) {
            target[p] = c;
            mvaddch(y, x + p++, c);
          }
      }
    }
    target[p + 1] = '\0';
    timeout(0);
    curs_set(0);
  }
};

struct World {
  World(Display *display) : display{display} {
    for (int x = 1; x < display->width - 1; x++) {
      walls.push_back(0);
    }
  }

  std::deque<int> walls;
  Display *display;
  int steps = 0;

  constexpr static int kRate = 2, kVGap = 2, kHGap = 10;

  int rand_wall() {
    int h = display->height;
    return (rand() % h / 2) + h / 4;
  }

  void step() {
    steps++;
    if (steps % kRate == 0) {
      walls.pop_front();
      switch (steps % (kRate * kHGap)) {
        case 0:
          walls.push_back(rand_wall());
          break;
        case kRate * 1:
        case kRate * 2:
          walls.push_back(walls.back());
          break;
        default:
          walls.push_back(0);
      }
    }
  }

  void draw() {
    for (int i = 0; i < walls.size(); i++) {
      int wall = walls[i];
      if (wall != 0) {
        for (int y = 1; y < display->height - 1; y++) {
          if (y == wall - kVGap - 1|| y == wall + kVGap + 1) {
            mvaddch(y, i + 1, '=');
          } else if (y < wall - kVGap || y > wall + kVGap) {
            mvaddch(y, i + 1, '*');
          }
        }
      }
    }
    mvprintw(display->height, 0, "Score: %d", score());
  }

  int score() { return std::max(0, (steps - 2) / (kRate * kHGap) - 2); }
};

struct Bird {
  Bird(Display *display) : y{display->height / 2.0}, display{display} {}

  static constexpr double kImpulse = -0.8, kGravity = 0.1;

  double y, dy = kImpulse;
  Display *display;

  void gravity() {
    dy += kGravity;
    y += dy;
  }

  void poke() { dy = kImpulse; }

  void draw() { draw('@'); }

  void draw(int c) {
    int h = std::round(y);
    h = std::max(1, std::min(h, display->height - 2));
    mvaddch(h, display->width / 2, c);
  }

  bool is_alive(World &world) {
    if (y <= 0 || y >= display->height) {
      return false;
    }
    int wall = world.walls[display->width / 2 - 1];
    if (wall != 0) {
      return y > wall - World::kVGap && y < wall + World::kVGap;
    }
    return true;
  }
};

struct Game {
  Game(Display *display) : display{display}, bird{display}, world{display} {}

  Display *display;
  Bird bird;
  World world;

  int run() {
    display->erase();
    const char *intro = "[Press SPACE to hop upwards]";
    mvprintw(display->height / 2 - 2,
             display->width / 2 - std::strlen(intro) / 2, intro);
    bird.draw();
    display->block_getch();
    while (bird.is_alive(world)) {
      int c = getch();
      if (c == 'q') {
        return -1;
      } else if (c != ERR) {
        while (getch() != ERR)
          ;  // clear repeat buffer
        bird.poke();
      }
      display->erase();
      world.step();
      world.draw();
      bird.gravity();
      bird.draw();
      display->refresh();
      std::this_thread::sleep_for(std::chrono::milliseconds{67});
    }
    bird.draw('X');
    display->refresh();
    return world.score();
  }
};

void print_scores(Display &display, HighScores &scores) {
  mvprintw(0, display.width + 4, "== High Scores ==");
  int i = 1;
  for (auto &line : scores.top_scores()) {
    mvprintw(i, display.width + 1, "%s", line.name.c_str());
    clrtoeol();
    mvprintw(i, display.width + 24, "%d", line.score);
    i++;
  }
}

int main(int argc, const char **argv) {
  srand(std::time(NULL));
  const char *filename = "/tmp/flappy-scores.db";
  if (argc > 1) {
    filename = argv[1];
  }
  Display display;
  HighScores scores{filename, display.height};

  while (true) {
    Game game{&display};

    int score = game.run();
    if (score < 0) {
      return 0;  // game quit early
    }

    /* Game over */
    mvprintw(display.height + 1, 0, "Game over!");
    print_scores(display, scores);

    /* Enter new high score */
    if (scores.is_best(score)) {
      mvprintw(display.height + 2, 0, "You have a high score!");
      mvprintw(display.height + 3, 0, "Enter name: ");
      char name[23] = {0};
      display.read_name(display.height + 3, 12, name, sizeof(name));
      if (std::strlen(name) == 0) {
        std::strcpy(name, "(anonymous)");
      }
      scores.insert_score(name, score);
      move(display.height + 3, 0);
      clrtoeol();
      print_scores(display, scores);
    }

    /* Handle quit/restart */
    mvprintw(display.height + 2, 0, "Press 'q' to quit, 'r' to retry.");
    int c;
    while ((c = display.block_getch()) != 'r') {
      if (c == 'q' || c == ERR) {
        return 0;
      }
    }
  }
  return 0;
}
<|endoftext|>


<commit_before>/* tntnet.cpp
 * Copyright (C) 2003-2005 Tommi Maekitalo
 *
 * This program 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 program 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 program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "tnt/tntnet.h"
#include "tnt/worker.h"
#include "tnt/listener.h"
#include "tnt/http.h"
#include "tnt/httpreply.h"
#include "tnt/sessionscope.h"

#include <cxxtools/tcpstream.h>
#include <cxxtools/log.h>

#include <config.h>

#ifndef TNTNET_CONF
# define TNTNET_CONF "/etc/tntnet.conf"
#endif

#ifndef TNTNET_PID
# define TNTNET_PID "/var/run/tntnet.pid"
#endif

log_define("tntnet.tntnet")

namespace
{
  void configureDispatcher(tnt::Dispatcher& dis, const tnt::Tntconfig& config)
  {
    typedef tnt::Dispatcher::CompidentType CompidentType;

    const tnt::Tntconfig::config_entries_type& params = config.getConfigValues();

    tnt::Tntconfig::config_entries_type::const_iterator vi;
    for (vi = params.begin(); vi != params.end(); ++vi)
    {
      const tnt::Tntconfig::config_entry_type& v = *vi;
      const tnt::Tntconfig::params_type& args = v.params;
      if (v.key == "MapUrl")
      {
        if (args.size() < 2)
        {
          std::ostringstream msg;
          msg << "invalid number of parameters (" << args.size() << ") in MapUrl";
          throw std::runtime_error(msg.str());
        }

        std::string url = args[0];

        CompidentType ci = CompidentType(args[1]);
        if (args.size() > 2)
        {
          ci.setPathInfo(args[2]);
          if (args.size() > 3)
            ci.setArgs(CompidentType::args_type(args.begin() + 3, args.end()));
        }

        dis.addUrlMapEntry(std::string(), url, ci);
      }
      else if (v.key == "VMapUrl")
      {
        if (args.size() < 3)
        {
          std::ostringstream msg;
          msg << "invalid number of parameters (" << args.size() << ") in VMapUrl";
          throw std::runtime_error(msg.str());
        }

        std::string vhost = args[0];
        std::string url = args[1];

        CompidentType ci = CompidentType(args[2]);
        if (args.size() > 3)
        {
          ci.setPathInfo(args[3]);
          if (args.size() > 4)
            ci.setArgs(CompidentType::args_type(args.begin() + 4, args.end()));
        }

        dis.addUrlMapEntry(vhost, url, ci);
      }
    }
  }
}

namespace tnt
{
  ////////////////////////////////////////////////////////////////////////
  // Tntnet
  //
  bool Tntnet::stop = false;

  void Tntnet::init(const Tntconfig& config)
  {
    minthreads = config.getValue<unsigned>("MinThreads", 5);
    maxthreads = config.getValue<unsigned>("MaxThreads", 100);
    threadstartdelay = config.getValue<unsigned>("ThreadStartDelay", 10);
    timersleep = config.getValue<unsigned>("TimerSleep", 10);
    Worker::setMinThreads(minthreads);
    Worker::setMaxRequestTime(config.getValue<unsigned>("MaxRequestTime", Worker::getMaxRequestTime()));
    Worker::setEnableCompression(config.getBoolValue("EnableCompression", Worker::getEnableCompression()));
    queue.setCapacity(config.getValue<unsigned>("QueueSize", queue.getCapacity()));
    Sessionscope::setDefaultTimeout(config.getValue<unsigned>("SessionTimeout", Sessionscope::getDefaultTimeout()));
    Listener::setBacklog(config.getValue<int>("ListenBacklog", Listener::getBacklog()));
    Listener::setListenRetry(config.getValue<int>("ListenRetry", Listener::getListenRetry()));
    Dispatcher::setMaxUrlMapCache(config.getValue<unsigned>("MaxUrlMapCache", Dispatcher::getMaxUrlMapCache()));

    Tntconfig::config_entries_type configSetEnv;
    config.getConfigValues("SetEnv", configSetEnv);
    for (Tntconfig::config_entries_type::const_iterator it = configSetEnv.begin();
         it != configSetEnv.end(); ++it)
    {
      if (it->params.size() >= 2)
      {
#ifdef HAVE_SETENV
        log_debug("setenv " << it->params[0] << "=\"" << it->params[1] << '"');
        ::setenv(it->params[0].c_str(), it->params[1].c_str(), 1);
#else
        std::string name  = it->params[0];
        std::string value = it->params[1];

        char* env = new char[name.size() + value.size() + 2];
        name.copy(env, name.size());
        env[name.size()] = '=';
        value.copy(env + name.size() + 1, value.size());
        env[name.size() + value.size() + 1] = '\0';

        log_debug("putenv(" << env << ')');
        ::putenv(env);
#endif
      }
    }

    configureDispatcher(d_dispatcher, config);

    // configure worker (static)
    Comploader::configure(config);

    // configure http
    HttpMessage::setMaxRequestSize(
      config.getValue("MaxRequestSize", HttpMessage::getMaxRequestSize()));
    Job::setSocketReadTimeout(
      config.getValue("SocketReadTimeout", Job::getSocketReadTimeout()));
    Job::setSocketWriteTimeout(
      config.getValue("SocketWriteTimeout", Job::getSocketWriteTimeout()));
    Job::setKeepAliveMax(
      config.getValue("KeepAliveMax", Job::getKeepAliveMax()));
    Job::setSocketBufferSize(
      config.getValue("BufferSize", Job::getSocketBufferSize()));
    HttpReply::setMinCompressSize(
      config.getValue("MinCompressSize", HttpReply::getMinCompressSize()));
    HttpReply::setKeepAliveTimeout(
      config.getValue("KeepAliveTimeout", HttpReply::getKeepAliveTimeout()));
    HttpReply::setDefaultContentType(
      config.getValue("DefaultContentType", HttpReply::getDefaultContentType()));

    // initialize listeners
    Tntconfig::config_entries_type configListen;
    config.getConfigValues("Listen", configListen);

    if (configListen.empty())
    {
      unsigned short int port = (getuid() == 0 ? 80 : 8000);
      log_info("no listeners defined - using ip 0.0.0.0 port " << port);
      listeners.insert(new tnt::Listener("0.0.0.0", port, queue));
    }
    else
    {
      for (Tntconfig::config_entries_type::const_iterator it = configListen.begin();
           it != configListen.end(); ++it)
      {
        if (it->params.empty())
          throw std::runtime_error("empty Listen-entry");

        unsigned short int port = 80;
        if (it->params.size() >= 2)
        {
          std::istringstream p(it->params[1]);
          p >> port;
          if (!p)
          {
            std::ostringstream msg;
            msg << "invalid port " << it->params[1];
            throw std::runtime_error(msg.str());
          }
        }

        std::string ip(it->params[0]);
        log_info("listen on ip " << ip << " port " << port);
        listeners.insert(new tnt::Listener(ip, port, queue));
      }
    }

#ifdef USE_SSL
    // initialize ssl-listener
    std::string defaultCertificateFile = config.getValue("SslCertificate");
    std::string defaultCertificateKey = config.getValue("SslKey");
    configListen.clear();
    config.getConfigValues("SslListen", configListen);

    for (Tntconfig::config_entries_type::const_iterator it = configListen.begin();
         it != configListen.end(); ++it)
    {
      if (it->params.empty())
        throw std::runtime_error("empty SslListen-entry");

      unsigned short int port = 443;
      if (it->params.size() >= 2)
      {
        std::istringstream p(it->params[1]);
        p >> port;
        if (!p)
        {
          std::ostringstream msg;
          msg << "invalid port " << it->params[1];
          throw std::runtime_error(msg.str());
        }
      }

      std::string certificateFile =
        it->params.size() >= 3 ? it->params[2]
                               : defaultCertificateFile;
      std::string certificateKey =
        it->params.size() >= 4 ? it->params[3] :
        it->params.size() >= 3 ? it->params[2] : defaultCertificateKey;

      if (certificateFile.empty())
        throw std::runtime_error("Ssl-certificate not configured");

      std::string ip(it->params[0]);
      log_info("listen on ip " << ip << " port " << port << " (ssl)");
      listeners.insert(new Ssllistener(certificateFile.c_str(),
          certificateKey.c_str(), ip, port, queue));
    }
#endif // USE_SSL

    log_debug("listeners.size()=" << listeners.size());
  }

  void Tntnet::run()
  {
    log_debug("worker-process");

    if (listeners.size() > minthreads)
    {
      log_warn("need at least one worker per listener - set MinThreads to " << listeners.size());
      minthreads = listeners.size();
    }

    if (maxthreads < minthreads)
    {
      log_warn("MaxThreads < MinThreads - set MaxThreads = MinThreads = " << minthreads);
      maxthreads = minthreads;
    }

    // initialize worker-process
    // create worker-threads
    log_info("create " << minthreads << " worker threads");
    for (unsigned i = 0; i < minthreads; ++i)
    {
      log_debug("create worker " << i);
      Worker* s = new Worker(*this);
      s->create();
    }

    // create poller-thread
    log_debug("start poller thread");
    pollerthread.create();

    log_debug("start timer thread");
    cxxtools::MethodThread<Tntnet, cxxtools::AttachedThread> timerThread(*this, &Tntnet::timerTask);
    timerThread.create();

    // mainloop
    cxxtools::Mutex mutex;
    while (!stop)
    {
      {
        cxxtools::MutexLock lock(mutex);
        queue.noWaitThreads.wait(lock);
      }

      if (stop)
        break;

      if (Worker::getCountThreads() < maxthreads)
      {
        log_info("create workerthread");
        Worker* s = new Worker(*this);
        s->create();
      }
      else
        log_info("max worker-threadcount " << maxthreads << " reached");

      if (threadstartdelay > 0)
        usleep(threadstartdelay * 1000);
    }

    log_warn("stopping Tntnet");

    // join-loop
    while (!listeners.empty())
    {
      listeners_type::value_type s = *listeners.begin();
      log_debug("remove listener from listener-list");
      listeners.erase(s);

      log_debug("request listener to stop");
      s->doStop();

      delete s;

      log_debug("listener stopped");
    }

    log_info("listeners stopped");
  }

  void Tntnet::timerTask()
  {
    log_debug("timer thread");

    while (!stop)
    {
      sleep(timersleep);
      getScopemanager().checkSessionTimeout();
      Worker::timer();
    }

    log_warn("stopping Tntnet");

    queue.noWaitThreads.signal();
    Worker::setMinThreads(0);
    pollerthread.doStop();
  }

  void Tntnet::shutdown()
  {
    stop = true;
  }
}
<commit_msg>there must be always one worker thread more than listeners<commit_after>/* tntnet.cpp
 * Copyright (C) 2003-2005 Tommi Maekitalo
 *
 * This program 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 program 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 program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "tnt/tntnet.h"
#include "tnt/worker.h"
#include "tnt/listener.h"
#include "tnt/http.h"
#include "tnt/httpreply.h"
#include "tnt/sessionscope.h"

#include <cxxtools/tcpstream.h>
#include <cxxtools/log.h>

#include <config.h>

#ifndef TNTNET_CONF
# define TNTNET_CONF "/etc/tntnet.conf"
#endif

#ifndef TNTNET_PID
# define TNTNET_PID "/var/run/tntnet.pid"
#endif

log_define("tntnet.tntnet")

namespace
{
  void configureDispatcher(tnt::Dispatcher& dis, const tnt::Tntconfig& config)
  {
    typedef tnt::Dispatcher::CompidentType CompidentType;

    const tnt::Tntconfig::config_entries_type& params = config.getConfigValues();

    tnt::Tntconfig::config_entries_type::const_iterator vi;
    for (vi = params.begin(); vi != params.end(); ++vi)
    {
      const tnt::Tntconfig::config_entry_type& v = *vi;
      const tnt::Tntconfig::params_type& args = v.params;
      if (v.key == "MapUrl")
      {
        if (args.size() < 2)
        {
          std::ostringstream msg;
          msg << "invalid number of parameters (" << args.size() << ") in MapUrl";
          throw std::runtime_error(msg.str());
        }

        std::string url = args[0];

        CompidentType ci = CompidentType(args[1]);
        if (args.size() > 2)
        {
          ci.setPathInfo(args[2]);
          if (args.size() > 3)
            ci.setArgs(CompidentType::args_type(args.begin() + 3, args.end()));
        }

        dis.addUrlMapEntry(std::string(), url, ci);
      }
      else if (v.key == "VMapUrl")
      {
        if (args.size() < 3)
        {
          std::ostringstream msg;
          msg << "invalid number of parameters (" << args.size() << ") in VMapUrl";
          throw std::runtime_error(msg.str());
        }

        std::string vhost = args[0];
        std::string url = args[1];

        CompidentType ci = CompidentType(args[2]);
        if (args.size() > 3)
        {
          ci.setPathInfo(args[3]);
          if (args.size() > 4)
            ci.setArgs(CompidentType::args_type(args.begin() + 4, args.end()));
        }

        dis.addUrlMapEntry(vhost, url, ci);
      }
    }
  }
}

namespace tnt
{
  ////////////////////////////////////////////////////////////////////////
  // Tntnet
  //
  bool Tntnet::stop = false;

  void Tntnet::init(const Tntconfig& config)
  {
    minthreads = config.getValue<unsigned>("MinThreads", 5);
    maxthreads = config.getValue<unsigned>("MaxThreads", 100);
    threadstartdelay = config.getValue<unsigned>("ThreadStartDelay", 10);
    timersleep = config.getValue<unsigned>("TimerSleep", 10);
    Worker::setMinThreads(minthreads);
    Worker::setMaxRequestTime(config.getValue<unsigned>("MaxRequestTime", Worker::getMaxRequestTime()));
    Worker::setEnableCompression(config.getBoolValue("EnableCompression", Worker::getEnableCompression()));
    queue.setCapacity(config.getValue<unsigned>("QueueSize", queue.getCapacity()));
    Sessionscope::setDefaultTimeout(config.getValue<unsigned>("SessionTimeout", Sessionscope::getDefaultTimeout()));
    Listener::setBacklog(config.getValue<int>("ListenBacklog", Listener::getBacklog()));
    Listener::setListenRetry(config.getValue<int>("ListenRetry", Listener::getListenRetry()));
    Dispatcher::setMaxUrlMapCache(config.getValue<unsigned>("MaxUrlMapCache", Dispatcher::getMaxUrlMapCache()));

    Tntconfig::config_entries_type configSetEnv;
    config.getConfigValues("SetEnv", configSetEnv);
    for (Tntconfig::config_entries_type::const_iterator it = configSetEnv.begin();
         it != configSetEnv.end(); ++it)
    {
      if (it->params.size() >= 2)
      {
#ifdef HAVE_SETENV
        log_debug("setenv " << it->params[0] << "=\"" << it->params[1] << '"');
        ::setenv(it->params[0].c_str(), it->params[1].c_str(), 1);
#else
        std::string name  = it->params[0];
        std::string value = it->params[1];

        char* env = new char[name.size() + value.size() + 2];
        name.copy(env, name.size());
        env[name.size()] = '=';
        value.copy(env + name.size() + 1, value.size());
        env[name.size() + value.size() + 1] = '\0';

        log_debug("putenv(" << env << ')');
        ::putenv(env);
#endif
      }
    }

    configureDispatcher(d_dispatcher, config);

    // configure worker (static)
    Comploader::configure(config);

    // configure http
    HttpMessage::setMaxRequestSize(
      config.getValue("MaxRequestSize", HttpMessage::getMaxRequestSize()));
    Job::setSocketReadTimeout(
      config.getValue("SocketReadTimeout", Job::getSocketReadTimeout()));
    Job::setSocketWriteTimeout(
      config.getValue("SocketWriteTimeout", Job::getSocketWriteTimeout()));
    Job::setKeepAliveMax(
      config.getValue("KeepAliveMax", Job::getKeepAliveMax()));
    Job::setSocketBufferSize(
      config.getValue("BufferSize", Job::getSocketBufferSize()));
    HttpReply::setMinCompressSize(
      config.getValue("MinCompressSize", HttpReply::getMinCompressSize()));
    HttpReply::setKeepAliveTimeout(
      config.getValue("KeepAliveTimeout", HttpReply::getKeepAliveTimeout()));
    HttpReply::setDefaultContentType(
      config.getValue("DefaultContentType", HttpReply::getDefaultContentType()));

    // initialize listeners
    Tntconfig::config_entries_type configListen;
    config.getConfigValues("Listen", configListen);

    if (configListen.empty())
    {
      unsigned short int port = (getuid() == 0 ? 80 : 8000);
      log_info("no listeners defined - using ip 0.0.0.0 port " << port);
      listeners.insert(new tnt::Listener("0.0.0.0", port, queue));
    }
    else
    {
      for (Tntconfig::config_entries_type::const_iterator it = configListen.begin();
           it != configListen.end(); ++it)
      {
        if (it->params.empty())
          throw std::runtime_error("empty Listen-entry");

        unsigned short int port = 80;
        if (it->params.size() >= 2)
        {
          std::istringstream p(it->params[1]);
          p >> port;
          if (!p)
          {
            std::ostringstream msg;
            msg << "invalid port " << it->params[1];
            throw std::runtime_error(msg.str());
          }
        }

        std::string ip(it->params[0]);
        log_info("listen on ip " << ip << " port " << port);
        listeners.insert(new tnt::Listener(ip, port, queue));
      }
    }

#ifdef USE_SSL
    // initialize ssl-listener
    std::string defaultCertificateFile = config.getValue("SslCertificate");
    std::string defaultCertificateKey = config.getValue("SslKey");
    configListen.clear();
    config.getConfigValues("SslListen", configListen);

    for (Tntconfig::config_entries_type::const_iterator it = configListen.begin();
         it != configListen.end(); ++it)
    {
      if (it->params.empty())
        throw std::runtime_error("empty SslListen-entry");

      unsigned short int port = 443;
      if (it->params.size() >= 2)
      {
        std::istringstream p(it->params[1]);
        p >> port;
        if (!p)
        {
          std::ostringstream msg;
          msg << "invalid port " << it->params[1];
          throw std::runtime_error(msg.str());
        }
      }

      std::string certificateFile =
        it->params.size() >= 3 ? it->params[2]
                               : defaultCertificateFile;
      std::string certificateKey =
        it->params.size() >= 4 ? it->params[3] :
        it->params.size() >= 3 ? it->params[2] : defaultCertificateKey;

      if (certificateFile.empty())
        throw std::runtime_error("Ssl-certificate not configured");

      std::string ip(it->params[0]);
      log_info("listen on ip " << ip << " port " << port << " (ssl)");
      listeners.insert(new Ssllistener(certificateFile.c_str(),
          certificateKey.c_str(), ip, port, queue));
    }
#endif // USE_SSL

    log_debug("listeners.size()=" << listeners.size());
  }

  void Tntnet::run()
  {
    log_debug("worker-process");

    if (listeners.size() >= minthreads)
    {
      log_warn("at least one more worker than listeners needed - set MinThreads to " << listeners.size() + 1);
      minthreads = listeners.size() + 1;
    }

    if (maxthreads < minthreads)
    {
      log_warn("MaxThreads < MinThreads - set MaxThreads = MinThreads = " << minthreads);
      maxthreads = minthreads;
    }

    // initialize worker-process
    // create worker-threads
    log_info("create " << minthreads << " worker threads");
    for (unsigned i = 0; i < minthreads; ++i)
    {
      log_debug("create worker " << i);
      Worker* s = new Worker(*this);
      s->create();
    }

    // create poller-thread
    log_debug("start poller thread");
    pollerthread.create();

    log_debug("start timer thread");
    cxxtools::MethodThread<Tntnet, cxxtools::AttachedThread> timerThread(*this, &Tntnet::timerTask);
    timerThread.create();

    // mainloop
    cxxtools::Mutex mutex;
    while (!stop)
    {
      {
        cxxtools::MutexLock lock(mutex);
        queue.noWaitThreads.wait(lock);
      }

      if (stop)
        break;

      if (Worker::getCountThreads() < maxthreads)
      {
        log_info("create workerthread");
        Worker* s = new Worker(*this);
        s->create();
      }
      else
        log_info("max worker-threadcount " << maxthreads << " reached");

      if (threadstartdelay > 0)
        usleep(threadstartdelay * 1000);
    }

    log_warn("stopping Tntnet");

    // join-loop
    while (!listeners.empty())
    {
      listeners_type::value_type s = *listeners.begin();
      log_debug("remove listener from listener-list");
      listeners.erase(s);

      log_debug("request listener to stop");
      s->doStop();

      delete s;

      log_debug("listener stopped");
    }

    log_info("listeners stopped");
  }

  void Tntnet::timerTask()
  {
    log_debug("timer thread");

    while (!stop)
    {
      sleep(timersleep);
      getScopemanager().checkSessionTimeout();
      Worker::timer();
    }

    log_warn("stopping Tntnet");

    queue.noWaitThreads.signal();
    Worker::setMinThreads(0);
    pollerthread.doStop();
  }

  void Tntnet::shutdown()
  {
    stop = true;
  }
}
<|endoftext|>


<commit_before>#include "collectors.h"
#include <fstream>
#include <iostream>
#include <chrono>

using namespace watcheD;
namespace collectors {

class CpuSpeedCollector : public Collector {
public:
	CpuSpeedCollector(std::shared_ptr<HttpServer> p_srv, Json::Value* p_cfg) : Collector("cpuspeed", p_srv, p_cfg) {
		std::string	line;
		std::string	id;
		std::ifstream	infile("/proc/cpuinfo");
		while(infile.good() && getline(infile, line)) {
			if (line.substr(0, line.find("\t")) == "processor") {
				id = line.substr(line.find(" ")+1,line.length());
				addRessource(id, "CPU "+id+" speed (Mhz)", "cpuspeed");
				ressources[id]->addProperty("MHz", "CPU speed (Mhz)", "number");
			}
		}
		addGetMetricRoute();
		if (infile.good())
			infile.close();
	}

	void collect() {
		std::string		line;
		std::string		value;
		std::string		id = "";
		std::ifstream	infile("/proc/cpuinfo");
		while(infile.good() && getline(infile, line)) {
			if (line.substr(0, line.find("\t")) == "processor")
				id = line.substr(line.find(" ")+1,line.length());
			else if (line.substr(0, line.find("\t")) == "cpu MHz" && id != "") {
				value = line.substr(line.find(" ",6)+1,line.length());
				ressources[id]->nextValue();
				ressources[id]->setProperty("MHz", atoi(value.c_str()));
			}
		}
		if (infile.good())
			infile.close();
	}
};

MAKE_PLUGIN_COLLECTOR(CpuSpeedCollector, cpuspeed)

}
<commit_msg>Improved cpu speed reading<commit_after>#include "collectors.h"
#include <dirent.h>
#include <sys/stat.h>
#include <fstream>
#include <streambuf>
#include <iostream>
#include <chrono>

using namespace watcheD;
namespace collectors {

class CpuSpeedCollector : public Collector {
public:
	CpuSpeedCollector(std::shared_ptr<HttpServer> p_srv, Json::Value* p_cfg) : Collector("cpuspeed", p_srv, p_cfg) {
		/*std::string	line;
		std::string	id;
		std::ifstream	infile("/proc/cpuinfo");
		while(infile.good() && getline(infile, line)) {
			if (line.substr(0, line.find("\t")) == "processor") {
				id = line.substr(line.find(" ")+1,line.length());
				addRessource(id, "CPU "+id+" speed (Mhz)", "cpuspeed");
				ressources[id]->addProperty("MHz", "CPU speed (Mhz)", "number");
			}
		}
		if (infile.good())
			infile.close();*/
		addGetMetricRoute();
	}

	void collect() {
		const std::string directory = "/sys/devices/system/cpu/cpufreq";
		DIR *dir;
		struct dirent *ent;
		struct stat st;
		dir = opendir(directory.c_str());
		if (dir != NULL) {
			while ((ent = readdir(dir)) != NULL) {
				const std::string file_name = ent->d_name;
				const std::string full_dir_name = directory + "/" + file_name;
				const std::string full_file_name = full_dir_name+"/scaling_cur_freq";

				int cpuid = -1;
				sscanf( file_name.c_str(), "%*[^0-9]%d", &cpuid);
				if (cpuid == -1)
					continue;

				if (file_name[0] == '.')
					continue;
				if (stat(full_dir_name.c_str(), &st) == -1)
					continue;
				const bool is_directory = (st.st_mode & S_IFDIR) != 0;
				if (!is_directory)
					continue;
				if (stat(full_file_name.c_str(), &st) == -1)
					continue;
				std::ifstream t(full_file_name.c_str());
				std::string str;

				// reading cpu speed value
				t.seekg(0, std::ios::end);
				str.reserve(t.tellg());
				t.seekg(0, std::ios::beg);
				str.assign((std::istreambuf_iterator<char>(t)),
					std::istreambuf_iterator<char>());
				if (ressources.find(file_name) == ressources.end()) {
					addRessource(file_name, "CPU "+std::to_string(cpuid)+" speed (Mhz)", "cpuspeed");
					ressources[file_name]->addProperty("MHz", "CPU speed (Mhz)", "number");
				}
				ressources[file_name]->nextValue();
				ressources[file_name]->setProperty("MHz", atoi(str.c_str())/1000);

			}
			closedir(dir);
		}
		/*std::string		line;
		std::string		value;
		std::string		id = "";
		std::ifstream	infile("/proc/cpuinfo");
		while(infile.good() && getline(infile, line)) {
			if (line.substr(0, line.find("\t")) == "processor")
				id = line.substr(line.find(" ")+1,line.length());
			else if (line.substr(0, line.find("\t")) == "cpu MHz" && id != "") {
				value = line.substr(line.find(" ",6)+1,line.length());
				ressources[id]->nextValue();
				ressources[id]->setProperty("MHz", atoi(value.c_str()));
			}
		}
		if (infile.good())
			infile.close();
		*/
	}
};

MAKE_PLUGIN_COLLECTOR(CpuSpeedCollector, cpuspeed)

}
<|endoftext|>


<commit_before>#line 2 "togo/gfx/types.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Graphics types.
@ingroup types
@ingroup gfx
*/

#pragma once

#include <togo/config.hpp>
#include <togo/types.hpp>
#include <togo/utility/traits.hpp>
#include <togo/utility/utility.hpp>

#include <initializer_list>

namespace togo {
namespace gfx {

/**
	@addtogroup gfx_display
	@{
*/

/// Graphics configuration flags.
enum class DisplayConfigFlags : unsigned {
	/// Empty flag.
	none = 0,
	/// Double-buffered display.
	double_buffered = 1 << 0,
};

/// Graphics configuration.
///
/// If either msaa_num_buffers or msaa_num_samples are 0, MSAA is
/// disabled.
struct DisplayConfig {
	struct ColorBits {
		unsigned red;
		unsigned green;
		unsigned blue;
		unsigned alpha;
	};

	/// Color buffer bits.
	gfx::DisplayConfig::ColorBits color_bits;

	/// Depth buffer bits.
	/// If this is 0, the depth buffer should be assumed unavailable.
	unsigned depth_bits;

	/// Stencil buffer bits.
	/// If this is 0, the stencil buffer should be assumed unavailable.
	unsigned stencil_bits;

	/// Number of MSAA buffers.
	unsigned msaa_num_buffers;
	/// Number of MSAA samples.
	unsigned msaa_num_samples;

	/// Miscellaneous flags.
	gfx::DisplayConfigFlags flags;
};

/// Display flags.
enum class DisplayFlags : unsigned {
	/// Empty flag.
	none = 0,
	/// Center window.
	centered = 1 << 0,
	/// Border-less window.
	borderless = 1 << 1,
	/// Full-screen window.
	fullscreen = 1 << 2,
	/// Re-sizable window.
	resizable = 1 << 3,

	owned_by_input_buffer = 1 << 4,
};

/// Display swap modes.
enum class DisplaySwapMode : unsigned {
	/// No screen synchronization.
	immediate = 0,

	/// Wait for at least one refresh cycle before swapping.
	wait_refresh,
};

/// Graphics display.
struct Display;

/** @} */ // end of doc-group gfx_display

/**
	@addtogroup gfx_renderer
	@{
*/

// TODO: Documentation & configuration
#define TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS 16

#define TOGO_GFX_NODE_NUM_COMMANDS 1024
#define TOGO_GFX_NODE_BUFFER_SIZE 8192

#define TOGO_GFX_CONFIG_NUM_VIEWPORTS 4
#define TOGO_GFX_CONFIG_NUM_PIPES 8
#define TOGO_GFX_PIPE_NUM_LAYERS 32
#define TOGO_GFX_LAYER_NUM_GENERATORS 16

#define TOGO_GFX_NUM_VERTEX_BUFFERS 2048
#define TOGO_GFX_NUM_INDEX_BUFFERS 2048
#define TOGO_GFX_NUM_TEXTURES 2048
#define TOGO_GFX_NUM_UNIFORMS 64
#define TOGO_GFX_NUM_PROGRAMS 128
#define TOGO_GFX_NUM_NODES 4

/// Buffer data binding mode.
enum class BufferDataBinding : unsigned {
	/// Buffer data never changes.
	fixed,
	/// Buffer data changes frequently.
	dynamic,

	NUM
};

/// Render node.
struct RenderNode;

/// Renderer.
struct Renderer;

/// Vertex attribute data type.
enum class VertexAttribType : unsigned {
	f32, f64,
	u8, u16, u32,
};

/// Unpacked vertex attribute.
struct VertexAttrib {
	gfx::VertexAttribType type;
	unsigned num_components;
	bool normalize_fixed;
};

// TODO: Encode attribute data to an integer to save memory
// TODO: Utilize C++14 constexpr features for compile-time construction
/// Vertex format.
struct VertexFormat {
	u32_fast _num_attribs;
	u32_fast _stride;
	gfx::VertexAttrib _attribs[TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS];
	u8 _offsets[TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS];

	inline /*constexpr*/ VertexFormat(
		std::initializer_list<gfx::VertexAttrib> const ilist
	) noexcept
		: _num_attribs(0)
		, _stride(0)
		, _attribs()
		, _offsets()
	{
		static constexpr unsigned const
		attrib_type_size[]{
			sizeof(f32), sizeof(f64),
			sizeof(u8), sizeof(u16), sizeof(u32)
		};
		for (auto const& attrib : ilist) {
			_attribs[_num_attribs] = attrib;
			_offsets[_num_attribs] = _stride;
			_stride += attrib_type_size[unsigned_cast(attrib.type)] * attrib.num_components;
			++_num_attribs;
		}
	}
};

enum : u32 {
	/// Null resource ID.
	ID_VALUE_NULL = 0,
};

/** @cond INTERNAL */
struct VertexBuffer;
struct IndexBuffer;
struct Texture;
struct Uniform;
struct Shader;

template<class /*R*/>
struct ResourceID {
	u32 _value;
};
/** @endcond */ // INTERNAL

/// Vertex buffer ID.
using VertexBufferID = ResourceID<VertexBuffer>;

/// Index buffer ID.
using IndexBufferID = ResourceID<IndexBuffer>;

/// Texture ID.
using TextureID = ResourceID<Texture>;

/// Uniform ID.
using UniformID = ResourceID<Uniform>;

/// Shader ID.
using ShaderID = ResourceID<Shader>;

/** @} */ // end of doc-group gfx_renderer

} // namespace gfx

/** @cond INTERNAL */
template<>
struct enable_enum_bitwise_ops<gfx::DisplayConfigFlags> : true_type {};

template<>
struct enable_enum_bitwise_ops<gfx::DisplayFlags> : true_type {};
/** @endcond */ // INTERNAL

} // namespace togo
<commit_msg>gfx/types: changed TOGO_GFX_CONFIG_NUM_VIEWPORTS to 8.<commit_after>#line 2 "togo/gfx/types.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Graphics types.
@ingroup types
@ingroup gfx
*/

#pragma once

#include <togo/config.hpp>
#include <togo/types.hpp>
#include <togo/utility/traits.hpp>
#include <togo/utility/utility.hpp>

#include <initializer_list>

namespace togo {
namespace gfx {

/**
	@addtogroup gfx_display
	@{
*/

/// Graphics configuration flags.
enum class DisplayConfigFlags : unsigned {
	/// Empty flag.
	none = 0,
	/// Double-buffered display.
	double_buffered = 1 << 0,
};

/// Graphics configuration.
///
/// If either msaa_num_buffers or msaa_num_samples are 0, MSAA is
/// disabled.
struct DisplayConfig {
	struct ColorBits {
		unsigned red;
		unsigned green;
		unsigned blue;
		unsigned alpha;
	};

	/// Color buffer bits.
	gfx::DisplayConfig::ColorBits color_bits;

	/// Depth buffer bits.
	/// If this is 0, the depth buffer should be assumed unavailable.
	unsigned depth_bits;

	/// Stencil buffer bits.
	/// If this is 0, the stencil buffer should be assumed unavailable.
	unsigned stencil_bits;

	/// Number of MSAA buffers.
	unsigned msaa_num_buffers;
	/// Number of MSAA samples.
	unsigned msaa_num_samples;

	/// Miscellaneous flags.
	gfx::DisplayConfigFlags flags;
};

/// Display flags.
enum class DisplayFlags : unsigned {
	/// Empty flag.
	none = 0,
	/// Center window.
	centered = 1 << 0,
	/// Border-less window.
	borderless = 1 << 1,
	/// Full-screen window.
	fullscreen = 1 << 2,
	/// Re-sizable window.
	resizable = 1 << 3,

	owned_by_input_buffer = 1 << 4,
};

/// Display swap modes.
enum class DisplaySwapMode : unsigned {
	/// No screen synchronization.
	immediate = 0,

	/// Wait for at least one refresh cycle before swapping.
	wait_refresh,
};

/// Graphics display.
struct Display;

/** @} */ // end of doc-group gfx_display

/**
	@addtogroup gfx_renderer
	@{
*/

// TODO: Documentation & configuration
#define TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS 16

#define TOGO_GFX_NODE_NUM_COMMANDS 1024
#define TOGO_GFX_NODE_BUFFER_SIZE 8192

#define TOGO_GFX_CONFIG_NUM_PIPES 8
#define TOGO_GFX_CONFIG_NUM_VIEWPORTS 8
#define TOGO_GFX_PIPE_NUM_LAYERS 32
#define TOGO_GFX_LAYER_NUM_GENERATORS 16

#define TOGO_GFX_NUM_VERTEX_BUFFERS 2048
#define TOGO_GFX_NUM_INDEX_BUFFERS 2048
#define TOGO_GFX_NUM_TEXTURES 2048
#define TOGO_GFX_NUM_UNIFORMS 64
#define TOGO_GFX_NUM_PROGRAMS 128
#define TOGO_GFX_NUM_NODES 4

/// Buffer data binding mode.
enum class BufferDataBinding : unsigned {
	/// Buffer data never changes.
	fixed,
	/// Buffer data changes frequently.
	dynamic,

	NUM
};

/// Render node.
struct RenderNode;

/// Renderer.
struct Renderer;

/// Vertex attribute data type.
enum class VertexAttribType : unsigned {
	f32, f64,
	u8, u16, u32,
};

/// Unpacked vertex attribute.
struct VertexAttrib {
	gfx::VertexAttribType type;
	unsigned num_components;
	bool normalize_fixed;
};

// TODO: Encode attribute data to an integer to save memory
// TODO: Utilize C++14 constexpr features for compile-time construction
/// Vertex format.
struct VertexFormat {
	u32_fast _num_attribs;
	u32_fast _stride;
	gfx::VertexAttrib _attribs[TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS];
	u8 _offsets[TOGO_GFX_VERTEXFORMAT_NUM_ATTRIBS];

	inline /*constexpr*/ VertexFormat(
		std::initializer_list<gfx::VertexAttrib> const ilist
	) noexcept
		: _num_attribs(0)
		, _stride(0)
		, _attribs()
		, _offsets()
	{
		static constexpr unsigned const
		attrib_type_size[]{
			sizeof(f32), sizeof(f64),
			sizeof(u8), sizeof(u16), sizeof(u32)
		};
		for (auto const& attrib : ilist) {
			_attribs[_num_attribs] = attrib;
			_offsets[_num_attribs] = _stride;
			_stride += attrib_type_size[unsigned_cast(attrib.type)] * attrib.num_components;
			++_num_attribs;
		}
	}
};

enum : u32 {
	/// Null resource ID.
	ID_VALUE_NULL = 0,
};

/** @cond INTERNAL */
struct VertexBuffer;
struct IndexBuffer;
struct Texture;
struct Uniform;
struct Shader;

template<class /*R*/>
struct ResourceID {
	u32 _value;
};
/** @endcond */ // INTERNAL

/// Vertex buffer ID.
using VertexBufferID = ResourceID<VertexBuffer>;

/// Index buffer ID.
using IndexBufferID = ResourceID<IndexBuffer>;

/// Texture ID.
using TextureID = ResourceID<Texture>;

/// Uniform ID.
using UniformID = ResourceID<Uniform>;

/// Shader ID.
using ShaderID = ResourceID<Shader>;

/** @} */ // end of doc-group gfx_renderer

} // namespace gfx

/** @cond INTERNAL */
template<>
struct enable_enum_bitwise_ops<gfx::DisplayConfigFlags> : true_type {};

template<>
struct enable_enum_bitwise_ops<gfx::DisplayFlags> : true_type {};
/** @endcond */ // INTERNAL

} // namespace togo
<|endoftext|>