<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: nadavs@google.com <Nadav Samet>
//         Jin Qing (http://blog.csdn.net/jq0123)

#include <iostream>
#include <boost/thread/thread.hpp>
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <zmq.hpp>

#include "proto/search.rpcz.h"

#include "rpcz/manager.hpp"
#include "rpcz/manager_ptr.hpp"
#include "rpcz/sync_event.hpp"
#include "rpcz/connection.hpp"

using namespace std;

namespace rpcz {

class delegate_resonder {
 public:
  explicit delegate_resonder(const replier& rep) :
      rspndr_(rep) {  // copy
  }
  void operator()(const rpc_error* e, const SearchResponse& resp) {
    if (e) return;
    rspndr_.respond(resp);
  }

 private:
  replier rspndr_;  // replier copy
};

class SearchServiceImpl : public SearchService {
 public:
  // Will take ownership of backend.
  SearchServiceImpl(SearchService_Stub* backend)
      : backend_(backend),
        cm_(manager::get()) {
  }

  ~SearchServiceImpl() {
  }

  virtual void Search(
      const SearchRequest& request,
      const replier& rep) {
    if (request.query() == "foo") {
      rep.respond_error(-4, "I don't like foo.");
    } else if (request.query() == "bar") {
      rep.respond_error(17, "I don't like bar.");
    } else if (request.query() == "delegate") {
      backend_->async_Search(request, delegate_resonder(rep));
      return;
    } else if (request.query() == "timeout") {
      // We "lose" the request. We are going to reply only when we get a request
      // for the query "delayed".
      boost::unique_lock<boost::mutex> lock(mu_);
      old_responder_.reset(new replier(rep));
      timeout_request_received.signal();
      return;
    } else if (request.query() == "delayed") {
      boost::unique_lock<boost::mutex> lock(mu_);
      if (old_responder_.get())
        old_responder_->respond(SearchResponse());
      rep.respond(SearchResponse());
    } else if (request.query() == "terminate") {
      rep.respond(SearchResponse());
      cm_->terminate();
    } else {
      SearchResponse response;
      response.add_results("The search for " + request.query());
      response.add_results("is great");
      rep.respond(response);
    }
  }

  rpcz::sync_event timeout_request_received;

 private:
  scoped_ptr<SearchService_Stub> backend_;
  boost::mutex mu_;
  scoped_ptr<replier> old_responder_;
  manager_ptr cm_;
};

// For handling complex delegated queries.
class BackendSearchServiceImpl : public SearchService {
 public:
  virtual void Search(
      const SearchRequest&,
      const replier& rep) {
    SearchResponse response;
    response.add_results("42!");
    rep.respond(response);
  }
};

class server_test : public ::testing::Test {
 public:
  server_test() :
      context_(new zmq::context_t(1)) /* scoped_ptr */ {
    EXPECT_TRUE(manager::is_destroyed());
    application::set_zmq_context(context_.get());
    application::set_manager_threads(10);
    frontend_server_.reset(new server);
    backend_server_.reset(new server);
    start_server();
  }

  ~server_test() {
    // terminate the context, which will cause the thread to quit.
    application::terminate();
    frontend_server_.reset();
    backend_server_.reset();
    frontend_service_.reset();
    backend_service_.reset();
    frontend_connection_.reset();
    backend_connection_.reset();

    EXPECT_TRUE(manager::is_destroyed());
    context_.reset();
  }

  void start_server() {
    backend_service_.reset(new BackendSearchServiceImpl);
    backend_server_->register_singleton_service(*backend_service_);
    backend_server_->bind("inproc://myserver.backend");
    backend_connection_.reset(new connection(
        "inproc://myserver.backend"));

    frontend_service_.reset(new SearchServiceImpl(
        new SearchService_Stub(backend_connection_)));
    frontend_server_->register_singleton_service(*frontend_service_);
    frontend_server_->bind("inproc://myserver.frontend");
    frontend_connection_.reset(new connection(
        "inproc://myserver.frontend"));
  }

protected:
  // destruct in reversed order
  scoped_ptr<zmq::context_t> context_;  // destruct last
  connection_ptr frontend_connection_;
  connection_ptr backend_connection_;
  scoped_ptr<SearchServiceImpl> frontend_service_;
  scoped_ptr<BackendSearchServiceImpl> backend_service_;
  // Server must destruct before service. (Or unregister services before destruct.)
  scoped_ptr<server> frontend_server_;
  scoped_ptr<server> backend_server_;
};

TEST_F(server_test, SimpleRequest) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("happiness");
  SearchResponse response = stub.Search(request);
  ASSERT_EQ(2, response.results_size());
  ASSERT_EQ("The search for happiness", response.results(0));
}

TEST_F(server_test, SimpleRequestAsync) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("happiness");

  struct hander {
    rpcz::sync_event sync;
    void operator()(const rpc_error* err, const SearchResponse& resp) {
      ASSERT_EQ(NULL, err);
      ASSERT_EQ(2, resp.results_size());
      ASSERT_EQ("The search for happiness", resp.results(0));
      sync.signal();
    }
  } hdl;
  stub.async_Search(request, boost::ref(hdl));
  hdl.sync.wait();
}

TEST_F(server_test, SimpleRequestWithError) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("foo");
  try {
    (void)stub.Search(request);
    ASSERT_TRUE(false);
  } catch (const rpc_error& e) {
    ASSERT_EQ("I don't like foo.", e.get_error_str());
  }
}

TEST_F(server_test, SimpleRequestWithTimeout) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("timeout");
  try {
    (void)stub.Search(request, 1);
    ASSERT_TRUE(false);
  } catch (const rpc_error& error) {
    ASSERT_EQ(error_code::TIMEOUT_EXPIRED, error.get_error_code());
    return;
  }
  ASSERT_TRUE(false);
}

TEST_F(server_test, SimpleRequestWithTimeoutAsync) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("timeout");

  struct handler {
    rpcz::sync_event sync;

    void operator()(const rpc_error* error, const SearchResponse &) {
      ASSERT_TRUE(NULL != error);
      ASSERT_EQ(error_code::TIMEOUT_EXPIRED, error->get_error_code());
      sync.signal();
    }
  } hdl;

  stub.async_Search(request,
      boost::ref(hdl),
      1/*timeout ms*/);
  hdl.sync.wait();
}

TEST_F(server_test, DelegatedRequest) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("delegate");
  SearchResponse response = stub.Search(request);
  ASSERT_EQ("42!", response.results(0));
}

TEST_F(server_test, EasyBlockingRequestRaisesExceptions) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  SearchResponse response;
  request.set_query("foo");
  try {
    stub.Search(request, &response);
    ASSERT_TRUE(false);
  } catch (const rpc_error& error) {
    ASSERT_EQ(-4, error.get_error_code());
  }
}

TEST_F(server_test, EasyBlockingRequestWithTimeout) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  SearchResponse response;
  request.set_query("timeout");
  try {
    stub.Search(request, 1, &response);
    ASSERT_TRUE(false);
  } catch (const rpc_error& error) {
    ASSERT_EQ(error_code::TIMEOUT_EXPIRED, error.get_error_code());
  }
  // We may get here before the timing out request was processed, and if we
  // just send delay right away, the server may be unable to reply.
  frontend_service_->timeout_request_received.wait();
  request.set_query("delayed");
  stub.Search(request, &response);
}

TEST_F(server_test, ConnectionManagerTermination) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("terminate");
  try {
    stub.Search(request, 1/*ms*/);
  } catch (const rpc_error& error) {
    ASSERT_EQ(error_code::TIMEOUT_EXPIRED, error.get_error_code());
  }
  LOG(INFO)<<"I'm here";
  manager::get()->run();
  LOG(INFO)<<"I'm there";
}

}  // namespace
<commit_msg>rename responder to replier<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: nadavs@google.com <Nadav Samet>
//         Jin Qing (http://blog.csdn.net/jq0123)

#include <iostream>
#include <boost/thread/thread.hpp>
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <zmq.hpp>

#include "proto/search.rpcz.h"

#include "rpcz/manager.hpp"
#include "rpcz/manager_ptr.hpp"
#include "rpcz/sync_event.hpp"
#include "rpcz/connection.hpp"

using namespace std;

namespace rpcz {

class delegate_resonder {
 public:
  explicit delegate_resonder(const replier& rep) :
      rspndr_(rep) {  // copy
  }
  void operator()(const rpc_error* e, const SearchResponse& resp) {
    if (e) return;
    rspndr_.respond(resp);
  }

 private:
  replier rspndr_;  // replier copy
};

class SearchServiceImpl : public SearchService {
 public:
  // Will take ownership of backend.
  SearchServiceImpl(SearchService_Stub* backend)
      : backend_(backend),
        cm_(manager::get()) {
  }

  ~SearchServiceImpl() {
  }

  virtual void Search(
      const SearchRequest& request,
      const replier& rep) {
    if (request.query() == "foo") {
      rep.respond_error(-4, "I don't like foo.");
    } else if (request.query() == "bar") {
      rep.respond_error(17, "I don't like bar.");
    } else if (request.query() == "delegate") {
      backend_->async_Search(request, delegate_resonder(rep));
      return;
    } else if (request.query() == "timeout") {
      // We "lose" the request. We are going to reply only when we get a request
      // for the query "delayed".
      boost::unique_lock<boost::mutex> lock(mu_);
      old_replier_.reset(new replier(rep));
      timeout_request_received.signal();
      return;
    } else if (request.query() == "delayed") {
      boost::unique_lock<boost::mutex> lock(mu_);
      if (old_replier_.get())
        old_replier_->respond(SearchResponse());
      rep.respond(SearchResponse());
    } else if (request.query() == "terminate") {
      rep.respond(SearchResponse());
      cm_->terminate();
    } else {
      SearchResponse response;
      response.add_results("The search for " + request.query());
      response.add_results("is great");
      rep.respond(response);
    }
  }

  rpcz::sync_event timeout_request_received;

 private:
  scoped_ptr<SearchService_Stub> backend_;
  boost::mutex mu_;
  scoped_ptr<replier> old_replier_;
  manager_ptr cm_;
};

// For handling complex delegated queries.
class BackendSearchServiceImpl : public SearchService {
 public:
  virtual void Search(
      const SearchRequest&,
      const replier& rep) {
    SearchResponse response;
    response.add_results("42!");
    rep.respond(response);
  }
};

class server_test : public ::testing::Test {
 public:
  server_test() :
      context_(new zmq::context_t(1)) /* scoped_ptr */ {
    EXPECT_TRUE(manager::is_destroyed());
    application::set_zmq_context(context_.get());
    application::set_manager_threads(10);
    frontend_server_.reset(new server);
    backend_server_.reset(new server);
    start_server();
  }

  ~server_test() {
    // terminate the context, which will cause the thread to quit.
    application::terminate();
    frontend_server_.reset();
    backend_server_.reset();
    frontend_service_.reset();
    backend_service_.reset();
    frontend_connection_.reset();
    backend_connection_.reset();

    EXPECT_TRUE(manager::is_destroyed());
    context_.reset();
  }

  void start_server() {
    backend_service_.reset(new BackendSearchServiceImpl);
    backend_server_->register_singleton_service(*backend_service_);
    backend_server_->bind("inproc://myserver.backend");
    backend_connection_.reset(new connection(
        "inproc://myserver.backend"));

    frontend_service_.reset(new SearchServiceImpl(
        new SearchService_Stub(backend_connection_)));
    frontend_server_->register_singleton_service(*frontend_service_);
    frontend_server_->bind("inproc://myserver.frontend");
    frontend_connection_.reset(new connection(
        "inproc://myserver.frontend"));
  }

protected:
  // destruct in reversed order
  scoped_ptr<zmq::context_t> context_;  // destruct last
  connection_ptr frontend_connection_;
  connection_ptr backend_connection_;
  scoped_ptr<SearchServiceImpl> frontend_service_;
  scoped_ptr<BackendSearchServiceImpl> backend_service_;
  // Server must destruct before service. (Or unregister services before destruct.)
  scoped_ptr<server> frontend_server_;
  scoped_ptr<server> backend_server_;
};

TEST_F(server_test, SimpleRequest) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("happiness");
  SearchResponse response = stub.Search(request);
  ASSERT_EQ(2, response.results_size());
  ASSERT_EQ("The search for happiness", response.results(0));
}

TEST_F(server_test, SimpleRequestAsync) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("happiness");

  struct hander {
    rpcz::sync_event sync;
    void operator()(const rpc_error* err, const SearchResponse& resp) {
      ASSERT_EQ(NULL, err);
      ASSERT_EQ(2, resp.results_size());
      ASSERT_EQ("The search for happiness", resp.results(0));
      sync.signal();
    }
  } hdl;
  stub.async_Search(request, boost::ref(hdl));
  hdl.sync.wait();
}

TEST_F(server_test, SimpleRequestWithError) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("foo");
  try {
    (void)stub.Search(request);
    ASSERT_TRUE(false);
  } catch (const rpc_error& e) {
    ASSERT_EQ("I don't like foo.", e.get_error_str());
  }
}

TEST_F(server_test, SimpleRequestWithTimeout) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("timeout");
  try {
    (void)stub.Search(request, 1);
    ASSERT_TRUE(false);
  } catch (const rpc_error& error) {
    ASSERT_EQ(error_code::TIMEOUT_EXPIRED, error.get_error_code());
    return;
  }
  ASSERT_TRUE(false);
}

TEST_F(server_test, SimpleRequestWithTimeoutAsync) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("timeout");

  struct handler {
    rpcz::sync_event sync;

    void operator()(const rpc_error* error, const SearchResponse &) {
      ASSERT_TRUE(NULL != error);
      ASSERT_EQ(error_code::TIMEOUT_EXPIRED, error->get_error_code());
      sync.signal();
    }
  } hdl;

  stub.async_Search(request,
      boost::ref(hdl),
      1/*timeout ms*/);
  hdl.sync.wait();
}

TEST_F(server_test, DelegatedRequest) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("delegate");
  SearchResponse response = stub.Search(request);
  ASSERT_EQ("42!", response.results(0));
}

TEST_F(server_test, EasyBlockingRequestRaisesExceptions) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  SearchResponse response;
  request.set_query("foo");
  try {
    stub.Search(request, &response);
    ASSERT_TRUE(false);
  } catch (const rpc_error& error) {
    ASSERT_EQ(-4, error.get_error_code());
  }
}

TEST_F(server_test, EasyBlockingRequestWithTimeout) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  SearchResponse response;
  request.set_query("timeout");
  try {
    stub.Search(request, 1, &response);
    ASSERT_TRUE(false);
  } catch (const rpc_error& error) {
    ASSERT_EQ(error_code::TIMEOUT_EXPIRED, error.get_error_code());
  }
  // We may get here before the timing out request was processed, and if we
  // just send delay right away, the server may be unable to reply.
  frontend_service_->timeout_request_received.wait();
  request.set_query("delayed");
  stub.Search(request, &response);
}

TEST_F(server_test, ConnectionManagerTermination) {
  SearchService_Stub stub(frontend_connection_);
  SearchRequest request;
  request.set_query("terminate");
  try {
    stub.Search(request, 1/*ms*/);
  } catch (const rpc_error& error) {
    ASSERT_EQ(error_code::TIMEOUT_EXPIRED, error.get_error_code());
  }
  LOG(INFO)<<"I'm here";
  manager::get()->run();
  LOG(INFO)<<"I'm there";
}

}  // namespace
<|endoftext|>


<commit_before>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#include <limits>
#include <sstream>
#include <string>
#include <tuple>

#include <gtest/gtest.h>

#include <commata/parse_csv.hpp>
#include <commata/record_extractor.hpp>

#include "BaseTest.hpp"
#include "tracking_allocator.hpp"

using namespace commata;
using namespace commata::test;

struct TestRecordExtractor : BaseTestWithParam<std::size_t>
{};

TEST_P(TestRecordExtractor, LeftmostKey)
{
    const wchar_t* s = L"key_a,key_b,value_a,value_b\n"
                       L"\"ka1\",kb1,va1,vb1\r\n"
                       L"ka2,kb2,va2,vb2\n"
                       L"ka1,kb3,vb3,\"vb3\"\r";
    std::wstringbuf in(s);
    std::wstringbuf out;
    std::wstring key_a = L"key_a";
    parse_csv(&in, make_record_extractor(&out, key_a, L"ka1"), GetParam());
    ASSERT_EQ(L"key_a,key_b,value_a,value_b\n"
              L"\"ka1\",kb1,va1,vb1\n"
              L"ka1,kb3,vb3,\"vb3\"\n",
              out.str());
}

TEST_P(TestRecordExtractor, InnerKey)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::ostringstream out;
    parse_csv(&in, make_record_extractor(out, "key_b",
        [](const char* first ,const char* last) {
            return std::string(first, last).substr(0, 3) == "kb1";
        }), GetParam());
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

TEST_P(TestRecordExtractor, NoSuchKey)
{
    const char* s = "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n";
    std::stringbuf in(s);
    std::stringbuf out;
    try {
        parse_csv(&in, make_record_extractor(&out, "key_c", "kc1"), GetParam());
        FAIL();
    } catch (const record_extraction_error& e) {
        ASSERT_NE(e.get_physical_position(), nullptr);
        ASSERT_EQ(0U, e.get_physical_position()->first);
        std::string message(e.what());
        ASSERT_TRUE(message.find("key_c") != std::string::npos);
    }
}

TEST_P(TestRecordExtractor, NoSuchField)
{
    const char* s = "key_a,key_b\r"
                    "k1\r"
                    "k0,k1,k2\r";
    std::stringbuf in(s);
    std::stringbuf out;
    ASSERT_TRUE(parse_csv(&in,
        make_record_extractor(&out, "key_b", "k1"), GetParam()));
    ASSERT_EQ("key_a,key_b\n"
              "k0,k1,k2\n",
              out.str());
}

INSTANTIATE_TEST_SUITE_P(, TestRecordExtractor, testing::Values(1, 10, 1024));

struct TestRecordExtractorLimit :
    testing::TestWithParam<std::tuple<bool, std::size_t>>
{};

TEST_P(TestRecordExtractorLimit, Basics)
{
    const auto includes_header = std::get<0>(GetParam());
    const auto max_record_num = std::get<1>(GetParam());
    const char* s = "key_a,key_b,value_a,value_b\n"
                    "ka1,kb1,va1,vb1\r"
                    "ka2,kb2,va2,vb2\n"
                    "ka1,kb3,vb3,vb3\n";
    std::stringbuf in(s);
    std::stringbuf out;
    const auto result = parse_csv(&in, make_record_extractor(
        &out, "key_a", "ka1", includes_header, max_record_num), 2);
    ASSERT_EQ(max_record_num > 1, result);
    std::string expected;
    if (includes_header) {
        expected += "key_a,key_b,value_a,value_b\n";
    }
    expected += "ka1,kb1,va1,vb1\n";
    if (max_record_num > 1) {
        expected += "ka1,kb3,vb3,vb3\n";
    }
    ASSERT_EQ(expected, out.str());
}

INSTANTIATE_TEST_SUITE_P(, TestRecordExtractorLimit,
    testing::Combine(
        testing::Bool(),
        testing::Values(1, std::numeric_limits<std::size_t>::max())));

struct TestRecordExtractorLimit0 : BaseTest
{};

TEST_F(TestRecordExtractorLimit0, IncludeHeader)
{
    const char* s = "key_a,key_b,value_a,value_b\r"
                    "ka1,kb1,va1,\"vb1\r";  // Ill-formed line, but not parsed
    std::stringbuf in(s);
    std::stringbuf out;
    const auto result = parse_csv(&in,
        make_record_extractor(&out, "key_a", "ka1", true, 0), 64);
    ASSERT_FALSE(result);
    std::string expected;
    ASSERT_EQ("key_a,key_b,value_a,value_b\n", out.str());
}

TEST_F(TestRecordExtractorLimit0, ExcludeHeaderNoSuchKey)
{
    const char* s = "key_a,key_b,value_a,value_b\r"
                    "ka1,kb1,va1,vb1\r";
    std::stringbuf in(s);
    std::stringbuf out;
    try {
        parse_csv(&in, make_record_extractor(&out, "key_A", "ka1", false, 0), 64);
        FAIL();
    } catch (const record_extraction_error& e) {
        ASSERT_NE(e.get_physical_position(), nullptr);
        ASSERT_EQ(0U, e.get_physical_position()->first);
    }
}

struct TestRecordExtractorIndexed : BaseTest
{};

TEST_F(TestRecordExtractorIndexed, Basics)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::ostringstream out;
    parse_csv(&in, make_record_extractor(out, 1,
        [](const char* first ,const char* last) {
            return std::string(first, last).substr(0, 3) == "kb1";
        }), 1024);
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

namespace {

struct final_predicate_for_value final
{
    bool operator()(const char* first, const char* last) const
    {
        return std::string(first, last).substr(0, 3) == "kb1";
    }
};

}

struct TestRecordExtractorFinalPredicateForValue : BaseTest
{};

TEST_F(TestRecordExtractorFinalPredicateForValue, Basics)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::stringbuf out;
    parse_csv(&in,
        make_record_extractor(&out, 1, final_predicate_for_value()), 1024);
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

struct TestRecordExtractorMiscellaneous : BaseTest
{};

TEST_F(TestRecordExtractorMiscellaneous, Reference)
{
    const char* s = "instrument,type\n"
                    "viola,string\n"
                    "tuba,brass\n"
                    "clarinet,woodwind\n"
                    "koto,string";
    std::stringbuf in(s);
    std::stringbuf out;

    const auto key_pred = [](auto begin, auto end) {
        return ((end - begin) >= 3) && (std::strncmp(begin, "typ", 3) == 0);
    };
    const auto value_pred = [](auto begin, auto end) {
        const std::string value(begin, end);
        return (value == "brass") || (value == "woodwind");
    };

    // Freaking VS2015 picks up parse_csv's overload for reference_wrappers
    // and complain about ambiguity, so we squelch it by force with explicit
    // template arguments
    auto ex = make_record_extractor(
        &out, std::ref(key_pred), std::ref(value_pred));
    parse_csv<std::char_traits<char>, decltype(ex)>(&in, std::move(ex));
    ASSERT_EQ("instrument,type\n"
              "tuba,brass\n"
              "clarinet,woodwind\n",
              out.str());
}

TEST_F(TestRecordExtractorMiscellaneous, Allocator)
{
    std::size_t total = 0;
    tracking_allocator<std::allocator<char>> alloc(total);

    // Long names are required to make sure that std::string uses its
    // allocator
    const char* s = "instrument_______,type\n"
                    "castanets________,idiophone\n"
                    "clarinet_________,woodwind\n";
    std::stringbuf in(s);
    std::stringbuf out;

    // ditto
    auto ex = make_record_extractor(std::allocator_arg, alloc, &out,
        "instrument_______", std::string("clarinet_________"));
    parse_csv<std::char_traits<char>, decltype(ex)>(&in, std::move(ex), 8U);
    ASSERT_GT(total, 0U);
}

namespace {

template <class RecordExtractor>
class record_extractor_wrapper
{
    RecordExtractor x_;
    bool in_header_field_value_;
    const char* buffer_end_;

public:
    using char_type = char;

    record_extractor_wrapper(RecordExtractor&& x) :
        x_(std::move(x)), in_header_field_value_(false), buffer_end_(nullptr)
    {}

    void start_buffer(const char* buffer_begin, const char* buffer_end)
    {
        x_.start_buffer(buffer_begin, buffer_end);
    }

    void end_buffer(const char* buffer_end)
    {
        x_.end_buffer(buffer_end);
        buffer_end_ = buffer_end;
    }

    void start_record(const char* record_begin)
    {
        x_.start_record(record_begin);
    }

    void end_record(const char* record_end)
    {
        x_.end_record(record_end);
    }

    void update(const char* first, const char* last)
    {
        if (x_.is_in_header() && !in_header_field_value_) {
            insert(first, '[');
            in_header_field_value_ = true;
        }
        x_.update(first, last);
    }

    void finalize(const char* first, const char* last)
    {
        if (x_.is_in_header()) {
            if (!in_header_field_value_) {
                insert(first, '[');
                in_header_field_value_ = false;
            }
            x_.update(first, last);
            insert(last, ']');
            x_.finalize(last, last);
        } else {
            x_.finalize(first, last);
        }
    }

private:
    void insert(const char* before, char c)
    {
        char s[2];
        s[0] = c;
        x_.end_buffer(before);
        x_.start_buffer(s, s + 1);
        x_.update(s, s + 1);
        x_.end_buffer(s + 1);
        x_.start_buffer(before, buffer_end_);
    }
};

}

TEST_F(TestRecordExtractorMiscellaneous, IsInHeader)
{
    const char* s = "instrument,type\n"
                    "castanets,idiophone\n"
                    "clarinet,woodwind\n";
    std::stringbuf in(s);
    std::stringbuf out;

    auto x = make_record_extractor(&out, "[instrument]", "clarinet");
    parse_csv(&in, record_extractor_wrapper<decltype(x)>(std::move(x)));

    ASSERT_STREQ("[instrument],[type]\n"
                 "clarinet,woodwind\n", out.str().c_str());
}

TEST_F(TestRecordExtractorMiscellaneous, IsInHeaderIndexed)
{
    const char* s = "instrument,type\n"
                    "castanets,idiophone\n"
                    "clarinet,woodwind\n";
    std::stringbuf in(s);
    std::stringbuf out;

    auto x = make_record_extractor(&out, 1U, "woodwind");
    parse_csv(&in, record_extractor_wrapper<decltype(x)>(std::move(x)));

    ASSERT_STREQ("[instrument],[type]\n"
                 "clarinet,woodwind\n", out.str().c_str());
}
<commit_msg>Improve tests of record extractors<commit_after>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#include <limits>
#include <sstream>
#include <string>
#include <tuple>

#include <gtest/gtest.h>

#include <commata/parse_csv.hpp>
#include <commata/record_extractor.hpp>

#include "BaseTest.hpp"
#include "tracking_allocator.hpp"

using namespace commata;
using namespace commata::test;

struct TestRecordExtractor : BaseTestWithParam<std::size_t>
{};

TEST_P(TestRecordExtractor, LeftmostKey)
{
    const wchar_t* s = L"key_a,key_b,value_a,value_b\n"
                       L"\"ka1\",kb1,va1,vb1\r\n"
                       L"ka2,kb2,va2,vb2\n"
                       L"ka1,kb3,vb3,\"vb3\"\r";
    std::wstringbuf in(s);
    std::wstringbuf out;
    std::wstring key_a = L"key_a";
    parse_csv(&in, make_record_extractor(&out, key_a, L"ka1"), GetParam());
    ASSERT_EQ(L"key_a,key_b,value_a,value_b\n"
              L"\"ka1\",kb1,va1,vb1\n"
              L"ka1,kb3,vb3,\"vb3\"\n",
              out.str());
}

TEST_P(TestRecordExtractor, InnerKey)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::ostringstream out;
    parse_csv(&in, make_record_extractor(out, "key_b",
        [](const char* first ,const char* last) {
            return std::string(first, last).substr(0, 3) == "kb1";
        }), GetParam());
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

TEST_P(TestRecordExtractor, NoSuchKey)
{
    const char* s = "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n";
    std::stringbuf in(s);
    std::stringbuf out;
    try {
        parse_csv(&in, make_record_extractor(&out, "key_c", "kc1"), GetParam());
        FAIL();
    } catch (const record_extraction_error& e) {
        ASSERT_NE(e.get_physical_position(), nullptr);
        ASSERT_EQ(0U, e.get_physical_position()->first);
        std::string message(e.what());
        ASSERT_TRUE(message.find("key_c") != std::string::npos);
    }
}

TEST_P(TestRecordExtractor, NoSuchField)
{
    const char* s = "key_a,key_b\r"
                    "k1\r"
                    "k0,k1,k2\r";
    std::stringbuf in(s);
    std::stringbuf out;
    ASSERT_TRUE(parse_csv(&in,
        make_record_extractor(&out, "key_b", "k1"), GetParam()));
    ASSERT_EQ("key_a,key_b\n"
              "k0,k1,k2\n",
              out.str());
}

INSTANTIATE_TEST_SUITE_P(, TestRecordExtractor, testing::Values(1, 10, 1024));

struct TestRecordExtractorLimit :
    testing::TestWithParam<std::tuple<bool, std::size_t>>
{};

TEST_P(TestRecordExtractorLimit, Basics)
{
    const auto includes_header = std::get<0>(GetParam());
    const auto max_record_num = std::get<1>(GetParam());
    const char* s = "key_a,key_b,value_a,value_b\n"
                    "ka1,kb1,va1,vb1\r"
                    "ka2,kb2,va2,vb2\n"
                    "ka1,kb3,vb3,vb3\n";
    std::stringbuf in(s);
    std::stringbuf out;
    const auto result = parse_csv(&in, make_record_extractor(&out,
        "key_a", std::string("ka1"), includes_header, max_record_num), 2);
    ASSERT_EQ(max_record_num > 1, result);
    std::string expected;
    if (includes_header) {
        expected += "key_a,key_b,value_a,value_b\n";
    }
    expected += "ka1,kb1,va1,vb1\n";
    if (max_record_num > 1) {
        expected += "ka1,kb3,vb3,vb3\n";
    }
    ASSERT_EQ(expected, out.str());
}

INSTANTIATE_TEST_SUITE_P(, TestRecordExtractorLimit,
    testing::Combine(
        testing::Bool(),
        testing::Values(1, std::numeric_limits<std::size_t>::max())));

struct TestRecordExtractorLimit0 : BaseTest
{};

TEST_F(TestRecordExtractorLimit0, IncludeHeader)
{
    const char* s = "key_a,key_b,value_a,value_b\r"
                    "ka1,kb1,va1,\"vb1\r";  // Ill-formed line, but not parsed
    std::stringbuf in(s);
    std::stringbuf out;
    const auto result = parse_csv(&in, make_record_extractor(
            &out, std::string("key_a"), "ka1", true, 0), 64);
    ASSERT_FALSE(result);
    std::string expected;
    ASSERT_EQ("key_a,key_b,value_a,value_b\n", out.str());
}

TEST_F(TestRecordExtractorLimit0, ExcludeHeaderNoSuchKey)
{
    const char* s = "key_a,key_b,value_a,value_b\r"
                    "ka1,kb1,va1,vb1\r";
    std::stringbuf in(s);
    std::stringbuf out;
    try {
        parse_csv(&in, make_record_extractor(
            &out, "key_A", "ka1", false, 0), 64);
        FAIL();
    } catch (const record_extraction_error& e) {
        ASSERT_NE(e.get_physical_position(), nullptr);
        ASSERT_EQ(0U, e.get_physical_position()->first);
    }
}

struct TestRecordExtractorIndexed : BaseTest
{};

TEST_F(TestRecordExtractorIndexed, Basics)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::ostringstream out;
    parse_csv(&in, make_record_extractor(out, 1,
        [](const char* first ,const char* last) {
            return std::string(first, last).substr(0, 3) == "kb1";
        }), 1024);
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

namespace {

struct final_predicate_for_value final
{
    bool operator()(const char* first, const char* last) const
    {
        return std::string(first, last).substr(0, 3) == "kb1";
    }
};

}

struct TestRecordExtractorFinalPredicateForValue : BaseTest
{};

TEST_F(TestRecordExtractorFinalPredicateForValue, Basics)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::stringbuf out;
    parse_csv(&in,
        make_record_extractor(&out, 1, final_predicate_for_value()), 1024);
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

struct TestRecordExtractorMiscellaneous : BaseTest
{};

TEST_F(TestRecordExtractorMiscellaneous, Reference)
{
    const char* s = "instrument,type\n"
                    "viola,string\n"
                    "tuba,brass\n"
                    "clarinet,woodwind\n"
                    "koto,string";
    std::stringbuf in(s);
    std::stringbuf out;

    const auto key_pred = [](auto begin, auto end) {
        return ((end - begin) >= 3) && (std::strncmp(begin, "typ", 3) == 0);
    };
    const auto value_pred = [](auto begin, auto end) {
        const std::string value(begin, end);
        return (value == "brass") || (value == "woodwind");
    };

    // Freaking VS2015 picks up parse_csv's overload for reference_wrappers
    // and complain about ambiguity, so we squelch it by force with explicit
    // template arguments
    auto ex = make_record_extractor(
        &out, std::ref(key_pred), std::ref(value_pred));
    parse_csv<std::char_traits<char>, decltype(ex)>(&in, std::move(ex));
    ASSERT_EQ("instrument,type\n"
              "tuba,brass\n"
              "clarinet,woodwind\n",
              out.str());
}

TEST_F(TestRecordExtractorMiscellaneous, Allocator)
{
    std::size_t total = 0;
    tracking_allocator<std::allocator<char>> alloc(total);

    // Long names are required to make sure that std::string uses its
    // allocator
    const char* s = "instrument_______,type\n"
                    "castanets________,idiophone\n"
                    "clarinet_________,woodwind\n";
    std::stringbuf in(s);
    std::stringbuf out;

    // ditto
    auto ex = make_record_extractor(std::allocator_arg, alloc, &out,
        "instrument_______", std::string("clarinet_________"));
    parse_csv<std::char_traits<char>, decltype(ex)>(&in, std::move(ex), 8U);
    ASSERT_GT(total, 0U);
}

namespace {

template <class RecordExtractor>
class record_extractor_wrapper
{
    RecordExtractor x_;
    bool in_header_field_value_;
    const char* buffer_end_;

public:
    using char_type = char;

    record_extractor_wrapper(RecordExtractor&& x) :
        x_(std::move(x)), in_header_field_value_(false), buffer_end_(nullptr)
    {}

    void start_buffer(const char* buffer_begin, const char* buffer_end)
    {
        x_.start_buffer(buffer_begin, buffer_end);
    }

    void end_buffer(const char* buffer_end)
    {
        x_.end_buffer(buffer_end);
        buffer_end_ = buffer_end;
    }

    void start_record(const char* record_begin)
    {
        x_.start_record(record_begin);
    }

    void end_record(const char* record_end)
    {
        x_.end_record(record_end);
    }

    void update(const char* first, const char* last)
    {
        if (x_.is_in_header() && !in_header_field_value_) {
            insert(first, '[');
            in_header_field_value_ = true;
        }
        x_.update(first, last);
    }

    void finalize(const char* first, const char* last)
    {
        if (x_.is_in_header()) {
            if (!in_header_field_value_) {
                insert(first, '[');
                in_header_field_value_ = false;
            }
            x_.update(first, last);
            insert(last, ']');
            x_.finalize(last, last);
        } else {
            x_.finalize(first, last);
        }
    }

private:
    void insert(const char* before, char c)
    {
        char s[2];
        s[0] = c;
        x_.end_buffer(before);
        x_.start_buffer(s, s + 1);
        x_.update(s, s + 1);
        x_.end_buffer(s + 1);
        x_.start_buffer(before, buffer_end_);
    }
};

}

TEST_F(TestRecordExtractorMiscellaneous, IsInHeader)
{
    const char* s = "instrument,type\n"
                    "castanets,idiophone\n"
                    "clarinet,woodwind\n";
    std::stringbuf in(s);
    std::stringbuf out;

    auto x = make_record_extractor(&out, "[instrument]", "clarinet");
    parse_csv(&in, record_extractor_wrapper<decltype(x)>(std::move(x)));

    ASSERT_STREQ("[instrument],[type]\n"
                 "clarinet,woodwind\n", out.str().c_str());
}

TEST_F(TestRecordExtractorMiscellaneous, IsInHeaderIndexed)
{
    const char* s = "instrument,type\n"
                    "castanets,idiophone\n"
                    "clarinet,woodwind\n";
    std::stringbuf in(s);
    std::stringbuf out;

    auto x = make_record_extractor(&out, 1U, "woodwind");
    parse_csv(&in, record_extractor_wrapper<decltype(x)>(std::move(x)));

    ASSERT_STREQ("[instrument],[type]\n"
                 "clarinet,woodwind\n", out.str().c_str());
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_INV_LOGIT_HPP
#define STAN_MATH_PRIM_FUN_INV_LOGIT_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/prim/fun/inv.hpp>
#include <stan/math/prim/functor/apply_scalar_unary.hpp>
#include <cmath>

namespace stan {
namespace math {

/**
 * Returns the inverse logit function applied to the argument.
 *
 * The inverse logit function is defined by
 *
 * \f$\mbox{logit}^{-1}(x) = \frac{1}{1 + \exp(-x)}\f$.
 *
 * This function can be used to implement the inverse link function
 * for logistic regression.
 *
 * The inverse to this function is logit.
 *
 \f[
 \mbox{inv\_logit}(y) =
 \begin{cases}
 \mbox{logit}^{-1}(y) & \mbox{if } -\infty\leq y \leq \infty \\[6pt]
 \textrm{NaN} & \mbox{if } y = \textrm{NaN}
 \end{cases}
 \f]

 \f[
 \frac{\partial\, \mbox{inv\_logit}(y)}{\partial y} =
 \begin{cases}
 \frac{\partial\, \mbox{logit}^{-1}(y)}{\partial y} & \mbox{if } -\infty\leq
 y\leq \infty \\[6pt] \textrm{NaN} & \mbox{if } y = \textrm{NaN} \end{cases} \f]

 \f[
 \mbox{logit}^{-1}(y) = \frac{1}{1 + \exp(-y)}
 \f]

 \f[
 \frac{\partial \, \mbox{logit}^{-1}(y)}{\partial y} =
 \frac{\exp(y)}{(\exp(y)+1)^2} \f]
 *
 * @param a Argument.
 * @return Inverse logit of argument.
 */
inline double inv_logit(double a) {
  using std::exp;
  if (a < 0) {
    double exp_a = exp(a);
    if (a < LOG_EPSILON) {
      return exp_a;
    }
    return exp_a / (1 + exp_a);
  }
  return inv(1 + exp(-a));
}

/**
 * Structure to wrap inv_logit() so that it can be vectorized.
 *
 * @tparam T type of variable
 * @param x variable
 * @return Inverse logit of x.
 */
struct inv_logit_fun {
  template <typename T>
  static inline T fun(const T& x) {
    return inv_logit(x);
  }
};

/**
 * Vectorized version of inv_logit().
 *
 * @tparam T type of container
 * @param x container
 * @return Inverse logit applied to each value in x.
 */
template <typename T>
inline auto inv_logit(const T& x) {
  return apply_scalar_unary<inv_logit_fun, T>::apply(x);
}

// TODO(Tadej): Eigen is introducing their implementation logistic() of this
// in 3.4. Use that once we switch to Eigen 3.4

}  // namespace math
}  // namespace stan

#endif
<commit_msg>add missing require<commit_after>#ifndef STAN_MATH_PRIM_FUN_INV_LOGIT_HPP
#define STAN_MATH_PRIM_FUN_INV_LOGIT_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/prim/fun/inv.hpp>
#include <stan/math/prim/functor/apply_scalar_unary.hpp>
#include <cmath>

namespace stan {
namespace math {

/**
 * Returns the inverse logit function applied to the argument.
 *
 * The inverse logit function is defined by
 *
 * \f$\mbox{logit}^{-1}(x) = \frac{1}{1 + \exp(-x)}\f$.
 *
 * This function can be used to implement the inverse link function
 * for logistic regression.
 *
 * The inverse to this function is logit.
 *
 \f[
 \mbox{inv\_logit}(y) =
 \begin{cases}
 \mbox{logit}^{-1}(y) & \mbox{if } -\infty\leq y \leq \infty \\[6pt]
 \textrm{NaN} & \mbox{if } y = \textrm{NaN}
 \end{cases}
 \f]

 \f[
 \frac{\partial\, \mbox{inv\_logit}(y)}{\partial y} =
 \begin{cases}
 \frac{\partial\, \mbox{logit}^{-1}(y)}{\partial y} & \mbox{if } -\infty\leq
 y\leq \infty \\[6pt] \textrm{NaN} & \mbox{if } y = \textrm{NaN} \end{cases} \f]

 \f[
 \mbox{logit}^{-1}(y) = \frac{1}{1 + \exp(-y)}
 \f]

 \f[
 \frac{\partial \, \mbox{logit}^{-1}(y)}{\partial y} =
 \frac{\exp(y)}{(\exp(y)+1)^2} \f]
 *
 * @param a Argument.
 * @return Inverse logit of argument.
 */
inline double inv_logit(double a) {
  using std::exp;
  if (a < 0) {
    double exp_a = exp(a);
    if (a < LOG_EPSILON) {
      return exp_a;
    }
    return exp_a / (1 + exp_a);
  }
  return inv(1 + exp(-a));
}

/**
 * Structure to wrap inv_logit() so that it can be vectorized.
 *
 * @tparam T type of variable
 * @param x variable
 * @return Inverse logit of x.
 */
struct inv_logit_fun {
  template <typename T>
  static inline T fun(const T& x) {
    return inv_logit(x);
  }
};

/**
 * Vectorized version of inv_logit().
 *
 * @tparam T type of container
 * @param x container
 * @return Inverse logit applied to each value in x.
 */
template <typename T,
          require_all_not_nonscalar_prim_or_rev_kernel_expression_t<
              T>* = nullptr>
inline auto inv_logit(const T& x) {
  return apply_scalar_unary<inv_logit_fun, T>::apply(x);
}

// TODO(Tadej): Eigen is introducing their implementation logistic() of this
// in 3.4. Use that once we switch to Eigen 3.4

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>#pragma once

#include <zmqpp/zmqpp.hpp>
#include "FakeGPIO.hpp"
#include <boost/property_tree/ptree.hpp>
#include "gtest/gtest.h"
#include "core/MessageBus.hpp"

namespace Leosac
{
    namespace Test
    {
        namespace Helper
        {
            /**
            * Helper function that create an object of type ModuleType (using conventional parameter) and run it.
            * This runs in "module"'s thread.
            */
            template<typename ModuleType>
            bool test_run_module(zmqpp::context *ctx, zmqpp::socket *pipe, const boost::property_tree::ptree &cfg)
            {
                {
                    ModuleType module(*ctx, pipe, cfg);

                    pipe->send(zmqpp::signal::ok);
                    module.run();
                }
                return true;
            }

            /**
            * Part of the `bus_read()` stuff.
            */
            bool bus_read_extract(zmqpp::message *)
            {
                return true;
            }

            /**
            * Default frame extraction function.
            */
            template<typename T, typename ...Content>
            bool bus_read_extract(zmqpp::message *m,
                    T first_arg,
                    Content... content)
            {
                if (std::is_same<const char *, T>::value)
                {
                    std::string value;
                    *m >> value;
                    if (strcmp(value.c_str(), reinterpret_cast<const char *>(first_arg)) != 0)
                        return false;
                     return bus_read_extract(m, content...);
                }

                T value;
                *m >> value;
                if (value != first_arg)
                    return false;

                return bus_read_extract(m, content...);
            }

            /**
            * Frame extraction method specialized (thanks to overloading) for `const char *`
            */
/*            template<typename ...Content>
            bool bus_read_extract(zmqpp::message *m, const char *first_arg, Content... content)
            {
                std::string value;
                *m >> value;

                std::cerr << "I AM HERE" << std::endl;
                if (strcmp(value.c_str(), first_arg) != 0)
                    return false;
                return bus_read_extract(m, content...);
            }*/

            /**
            * Make a blocking read on the bus, return true if content match the message.
            * false otherwise.
            */
            template<typename ...Content>
            bool bus_read(zmqpp::socket &sub, Content... content)
            {
                zmqpp::message msg;

                if (!sub.receive(msg))
                    return false;
                return bus_read_extract(&msg, content...);
            }

            /**
            * Base class for test fixtures, it defines a ZMQ context, a BUS and a sub socket connect to the bus.
            */
            class TestHelper : public ::testing::Test
            {
            private:
                /**
                * Called in the module's actor's thread.
                * Override this: Construct configuration for the module then `run_test_module()` with appropriate parameters.
                */
                virtual bool run_module(zmqpp::socket *pipe) = 0;

            public:

                TestHelper() :
                        ctx_(),
                        bus_(ctx_),
                        bus_sub_(ctx_, zmqpp::socket_type::sub),
                        bus_push_(ctx_, zmqpp::socket_type::push),
                        module_actor_(nullptr)
                {
                    bus_sub_.connect("inproc://zmq-bus-pub");
                    bus_push_.connect("inproc://zmq-bus-pull");
                }

                virtual ~TestHelper()
                {
                }

                /**
                * We need this 2-step initialization to prevent calling virtual method (run_module) in constructor.
                */
                virtual void SetUp() override final
                {
                    module_actor_ = std::unique_ptr<zmqpp::actor>(new zmqpp::actor(std::bind(&TestHelper::run_module, this, std::placeholders::_1)));
                }

                /**
                * A context for the test case
                */
                zmqpp::context ctx_;

                /**
                * A BUS identical to the one spawned by core.
                */
                MessageBus bus_;

                /**
                * A SUB socket connected to the previous bus.
                */
                zmqpp::socket bus_sub_;

                /**
                * A PUSH socket to write on the bus.
                */
                zmqpp::socket bus_push_;

                /**
                * An actor, to run the module code the same way it would be run by the core.
                * Does NOT subscribe to anything.
                */
                std::unique_ptr<zmqpp::actor> module_actor_;
            };
        }
    }
}
<commit_msg>fix template magic in TestHelper<commit_after>#pragma once

#include <zmqpp/zmqpp.hpp>
#include "FakeGPIO.hpp"
#include <boost/property_tree/ptree.hpp>
#include "gtest/gtest.h"
#include "core/MessageBus.hpp"

namespace Leosac
{
    namespace Test
    {
        namespace Helper
        {
            /**
            * Helper function that create an object of type ModuleType (using conventional parameter) and run it.
            * This runs in "module"'s thread.
            */
            template<typename ModuleType>
            bool test_run_module(zmqpp::context *ctx, zmqpp::socket *pipe, const boost::property_tree::ptree &cfg)
            {
                {
                    ModuleType module(*ctx, pipe, cfg);

                    pipe->send(zmqpp::signal::ok);
                    module.run();
                }
                return true;
            }

            /**
            * Part of the `bus_read()` stuff.
            */
            bool bus_read_extract(zmqpp::message *)
            {
                return true;
            }

            template<typename ...Content>
            bool bus_read_extract(zmqpp::message *m, const char *first_arg, Content... content);

            /**
            * Default frame extraction function.
            *
            * Disabled for `const char *`.
            */
            template<typename T, typename ...Content>
            typename std::enable_if<!std::is_same<const char *, T>::value, bool>::type bus_read_extract(zmqpp::message *m,
                    T first_arg,
                    Content... content)
            {
                T value;
                *m >> value;
                if (value != first_arg)
                    return false;

                return bus_read_extract(m, content...);
            }

            /**
            * Frame extraction method specialized (thanks to overloading) for `const char *`
            */
            template<typename ...Content>
            bool bus_read_extract(zmqpp::message *m, const char *first_arg, Content... content)
            {
                std::string value;
                *m >> value;

                if (strcmp(value.c_str(), first_arg) != 0)
                    return false;
                return bus_read_extract(m, content...);
            }

            /**
            * Make a blocking read on the bus, return true if content match the message.
            * false otherwise.
            */
            template<typename ...Content>
            bool bus_read(zmqpp::socket &sub, Content... content)
            {
                zmqpp::message msg;

                if (!sub.receive(msg))
                    return false;
                return bus_read_extract(&msg, content...);
            }

            /**
            * Base class for test fixtures, it defines a ZMQ context, a BUS and a sub socket connect to the bus.
            */
            class TestHelper : public ::testing::Test
            {
            private:
                /**
                * Called in the module's actor's thread.
                * Override this: Construct configuration for the module then `run_test_module()` with appropriate parameters.
                */
                virtual bool run_module(zmqpp::socket *pipe) = 0;

            public:

                TestHelper() :
                        ctx_(),
                        bus_(ctx_),
                        bus_sub_(ctx_, zmqpp::socket_type::sub),
                        bus_push_(ctx_, zmqpp::socket_type::push),
                        module_actor_(nullptr)
                {
                    bus_sub_.connect("inproc://zmq-bus-pub");
                    bus_push_.connect("inproc://zmq-bus-pull");
                }

                virtual ~TestHelper()
                {
                }

                /**
                * We need this 2-step initialization to prevent calling virtual method (run_module) in constructor.
                */
                virtual void SetUp() override final
                {
                    module_actor_ = std::unique_ptr<zmqpp::actor>(new zmqpp::actor(std::bind(&TestHelper::run_module, this, std::placeholders::_1)));
                }

                /**
                * A context for the test case
                */
                zmqpp::context ctx_;

                /**
                * A BUS identical to the one spawned by core.
                */
                MessageBus bus_;

                /**
                * A SUB socket connected to the previous bus.
                */
                zmqpp::socket bus_sub_;

                /**
                * A PUSH socket to write on the bus.
                */
                zmqpp::socket bus_push_;

                /**
                * An actor, to run the module code the same way it would be run by the core.
                * Does NOT subscribe to anything.
                */
                std::unique_ptr<zmqpp::actor> module_actor_;
            };
        }
    }
}
<|endoftext|>


<commit_before>// Catch
#include <catch.hpp>

// Mantella
#include <mantella>

class TestPrintable : public mant::Printable {
  public:
    std::string to_string() const noexcept override {
      return "ThisIsTestPrintable";
    }
};

TEST_CASE("string: to_string(Printable)", "") {
  SECTION("Returns the specified class name.") {
    TestPrintable testPrintable;

    CHECK(mant::to_string(testPrintable) == "ThisIsTestPrintable");
  }
}

TEST_CASE("string: to_string(Printable*)", "") {
  SECTION("Returns the specified class name.") {
    mant::Printable* testPrintable = new TestPrintable;

    CHECK(mant::to_string(testPrintable) == "ThisIsTestPrintable");
  }

  SECTION("Will also work with std::shared_ptr.") {
    std::shared_ptr<mant::Printable> testPrintable = std::shared_ptr<mant::Printable>(new TestPrintable);

    CHECK(mant::to_string(testPrintable) == "ThisIsTestPrintable");
  }
}

TEST_CASE("string: endsWith", "") {
  SECTION("Finds various subsets of endings.") {
    CHECK(mant::endsWith("input.serialised", ".serialised") == true);
    CHECK(mant::endsWith("input.serialised", "d") == true);
    CHECK(mant::endsWith("input.serialised", "put.serialised") == true);
    CHECK(mant::endsWith("input.serialised", "serialised") == true);
  }

  SECTION("Recognised the input itself as an ending.") {
    CHECK(mant::endsWith("input.serialised", "input.serialised") == true);
  }

  SECTION("Ignores substrings of the input, if something from the ending is missing.") {
    CHECK(mant::endsWith("input.serialised", ".serialise") == false);
    CHECK(mant::endsWith("input.serialised", "erialise") == false);
  }

  SECTION("Ignores any string not occuring within the input.") {
    CHECK(mant::endsWith("input.serialised", ".mat") == false);
  }

}

<commit_msg>test: Only testing usage with std::shared_ptr<commit_after>// Catch
#include <catch.hpp>

// Mantella
#include <mantella>

class TestPrintable : public mant::Printable {
  public:
    std::string to_string() const noexcept override {
      return "ThisIsTestPrintable";
    }
};

TEST_CASE("string: to_string(Printable)", "") {
  SECTION("Returns the specified class name.") {
    TestPrintable testPrintable;

    CHECK(mant::to_string(testPrintable) == "ThisIsTestPrintable");
  }
}

TEST_CASE("string: to_string(Printable*)", "") {
  SECTION("Returns the specified class name.") {
    std::shared_ptr<mant::Printable> testPrintable = std::shared_ptr<mant::Printable>(new TestPrintable);

    CHECK(mant::to_string(testPrintable) == "ThisIsTestPrintable");
  }
}

TEST_CASE("string: endsWith", "") {
  SECTION("Finds various subsets of endings.") {
    CHECK(mant::endsWith("input.serialised", ".serialised") == true);
    CHECK(mant::endsWith("input.serialised", "d") == true);
    CHECK(mant::endsWith("input.serialised", "put.serialised") == true);
    CHECK(mant::endsWith("input.serialised", "serialised") == true);
  }

  SECTION("Recognised the input itself as an ending.") {
    CHECK(mant::endsWith("input.serialised", "input.serialised") == true);
  }

  SECTION("Ignores substrings of the input, if something from the ending is missing.") {
    CHECK(mant::endsWith("input.serialised", ".serialise") == false);
    CHECK(mant::endsWith("input.serialised", "erialise") == false);
  }

  SECTION("Ignores any string not occuring within the input.") {
    CHECK(mant::endsWith("input.serialised", ".mat") == false);
  }

}

<|endoftext|>


<commit_before>//
//  IsingGridTest.cpp
//  jdemon
//
//  Created by Mark Larus on 3/11/13.
//  Copyright (c) 2013 Kenyon College. All rights reserved.
//

#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
#include <algorithm>
#include <set>
#include <sstream>
#include <map>

#include "IsingGrid.h"

using namespace boost::unit_test;
using namespace Ising;
typedef std::set<Ising::Cell*> CellSet;

struct EvenIsingGridFixture {
    Ising::Grid grid;
    EvenIsingGridFixture() : grid(6) {}
};

BOOST_FIXTURE_TEST_SUITE(IsingGridTest, EvenIsingGridFixture)

BOOST_AUTO_TEST_CASE( oddGridInvalid ) {
    BOOST_REQUIRE_THROW(Grid k(3), InvalidGridSize);
}

BOOST_AUTO_TEST_CASE( tooSmallGrid ) {
    BOOST_REQUIRE_THROW(Grid k(2), InvalidGridSize);
}

BOOST_AUTO_TEST_CASE( testEvenOddIteratorsDisjoint__evenGrid ) {
    BOOST_REQUIRE_EQUAL(grid.getDimension()%2, 0);
    CellSet evenSet;
    evenSet.insert(grid.evens.begin(),grid.evens.end());
    CellSet oddSet;
    oddSet.insert(grid.odds.begin(),grid.odds.end());
    size_t count = 0;

    for (CellSet::iterator it = evenSet.begin(); it!=evenSet.end(); ++it) {
        BOOST_CHECK(!oddSet.count(*it));
        ++count;
        BOOST_REQUIRE_LE(count, grid.size());
    }
    count = 0;
    for (CellSet::iterator it = oddSet.begin(); it!=oddSet.end(); ++it) {
        BOOST_CHECK(!evenSet.count(*it));
        ++count;
        BOOST_REQUIRE_LE(count, grid.size());
    }
}

BOOST_AUTO_TEST_CASE( testEvenCellsCount ) {
    int count = 0;
    for (Grid::subset::iterator it = grid.evens.begin(); it!=grid.evens.end(); ++it) {
        ++count;
        // Infinite loop protection.
        BOOST_REQUIRE_LE(count, grid.size());
    }
    BOOST_REQUIRE_EQUAL(count,grid.size()/2);
}

BOOST_AUTO_TEST_CASE( testOddCellsCount ) {
    int count = 0;
    for (Grid::subset::iterator it = grid.odds.begin(); it!=grid.odds.end(); ++it) {
        ++count;
        // Infinite loop protection:
        BOOST_REQUIRE_LE(count, grid.size());
    }
    BOOST_REQUIRE_EQUAL(count,grid.size()/2);
}

BOOST_AUTO_TEST_CASE( testAllCellsCount ) {
    int count = 0;
    for (Grid::iterator it = grid.begin(); it!=grid.end(); ++it) {
        ++count;
        // Infinite loop protection:
        BOOST_REQUIRE_LE(count, grid.size());
    }
    BOOST_REQUIRE_EQUAL(count, grid.size());
}

BOOST_AUTO_TEST_CASE( testAllCellsInEvenOdd ) {
    CellSet evenOddSet, allSet;
    evenOddSet.insert(grid.evens.begin(), grid.evens.end());
    evenOddSet.insert(grid.odds.begin(),grid.odds.end());
    allSet.insert(grid.begin(),grid.end());

    for (CellSet::iterator it = allSet.begin(); it!=allSet.end(); ++it) {
        BOOST_CHECK(evenOddSet.count(*it));
    }

    for (CellSet::iterator it = evenOddSet.begin(); it!=evenOddSet.end(); ++it) {
        BOOST_CHECK(allSet.count(*it));
    }
}

BOOST_AUTO_TEST_CASE( testUniqueNeighbors ) {
    size_t loops = 0;
    for(Grid::iterator it = grid.begin(); it!=grid.end(); ++it) {
        Cell::Neighbors neighbors = (*it)->getNeighbors();
        CellSet neighborSet(neighbors.begin(),neighbors.end());

        BOOST_CHECK_EQUAL(neighborSet.size(), neighbors.size());

        // I wouldn't consider this an important unit test
        // But we might want to know if this changed:
        BOOST_CHECK_EQUAL(neighbors.size(), 4);
        BOOST_REQUIRE_LE(loops, grid.size());
    }
}

BOOST_AUTO_TEST_CASE( testNeighborsRelation_evenGrid ) {
    CellSet evenNeighbors, evenCells;
    CellSet oddNeighbors, oddCells;
    size_t loopGuard = 0;
    for (Grid::subset::iterator it = grid.evens.begin(); it!=grid.evens.end(); ++it) {
        ++loopGuard;
        evenCells.insert(*it);
        Cell::Neighbors neighbors = (*it)->getNeighbors();
        evenNeighbors.insert(neighbors.begin(),neighbors.end());
        BOOST_REQUIRE_LE(loopGuard, grid.size());
    }
    CellSet evenIntersection;
    std::insert_iterator<CellSet> insertionIterator(evenIntersection,evenIntersection.end());
    std::set_intersection(evenNeighbors.begin(), evenNeighbors.end(), evenCells.begin(), evenCells.end(), insertionIterator);

    BOOST_CHECK(evenIntersection.empty());

    BOOST_CHECK(!oddNeighbors.count(*grid.begin()));

    loopGuard = 0;
    for (Grid::subset::iterator it = grid.odds.begin(); it != grid.odds.end(); ++it) {
        ++loopGuard;
        oddCells.insert(*it);
        Cell::Neighbors neighbors = (*it)->getNeighbors();
        oddNeighbors.insert(neighbors.begin(),neighbors.end());
        BOOST_REQUIRE_LE(loopGuard, grid.size());
    }
    CellSet oddIntersection;
    std::insert_iterator<CellSet> oddInsertionIterator(evenIntersection,evenIntersection.end());
    std::set_intersection(oddNeighbors.begin(), oddNeighbors.end(), oddCells.begin(), oddCells.end(), oddInsertionIterator);
    BOOST_CHECK(oddIntersection.empty());

    BOOST_CHECK_EQUAL_COLLECTIONS(evenNeighbors.begin(), evenNeighbors.end(), oddCells.begin(), oddCells.end());
    BOOST_CHECK_EQUAL_COLLECTIONS(oddNeighbors.begin(), oddNeighbors.end(), evenCells.begin(), evenCells.end());
}

BOOST_AUTO_TEST_CASE( gridSize ) {
    BOOST_REQUIRE_EQUAL(grid.size(),grid.getDimension()*grid.getDimension());
}

BOOST_AUTO_TEST_CASE( testGetDimension ) {
    Grid grid(10);
    BOOST_REQUIRE_EQUAL(grid.getDimension(),10);
}

BOOST_AUTO_TEST_CASE( testNeighborsTransitive ) {
    size_t loops = 0;
    for(Grid::iterator it = grid.begin(); it!=grid.end(); ++it) {
        size_t innerLoops = 0;
        Cell::Neighbors neighbors = (*it)->getNeighbors();
        for (Cell::Neighbors::iterator neighbor = neighbors.begin(); neighbor!=neighbors.end(); ++neighbor) {
            Cell::Neighbors reverseNeighbors = (*neighbor)->getNeighbors();
            long count = std::count(reverseNeighbors.begin(), reverseNeighbors.end(), *it);
            BOOST_CHECK_EQUAL(count, 1);
            BOOST_REQUIRE_LE(innerLoops, neighbors.size());
            ++innerLoops;
        }
        ++loops;
        BOOST_REQUIRE_LE(loops, grid.size());
    }
}

BOOST_AUTO_TEST_CASE( testSetValue ) {
    Cell &cell = *grid[5];
    cell.setValue(0);
    BOOST_CHECK_EQUAL(cell.getValue(), 0);
    cell.setValue(1);
    BOOST_CHECK_EQUAL(cell.getValue(), 1);
    BOOST_REQUIRE_THROW(cell.setValue(2), InvalidCellValue);
    BOOST_REQUIRE_THROW(cell.setValue(-1), InvalidCellValue);
}

BOOST_AUTO_TEST_CASE( testRandomAccess ) {
    // The only interface contract here is that different grid indexes
    // return different cell pointers, and that an invalid index throws.
    CellSet cells;
    size_t size = grid.size();
    for (size_t k = 0; k != grid.size(); ++k) {
        cells.insert(grid[k]);
    }
    BOOST_REQUIRE(cells.size()==size);
    BOOST_REQUIRE_THROW(grid[2*size], InvalidGridIndex);
}

BOOST_AUTO_TEST_CASE( testEnergy ) {
    BOOST_FOREACH(Cell *center, std::make_pair(grid.begin(),grid.end())) {
        Cell::Neighbors neighbors = center->getNeighbors();
        for (int k = 0; k != (1 << neighbors.size()); ++k) {
            int highNeighbors = 0;
            for(int neighbor = 0; neighbor < neighbors.size(); ++neighbor) {
                int value = (k >> neighbor) & 1;
                highNeighbors += value;
                neighbors[neighbor]->setValue(value);
            }
            center->setValue(0);
            BOOST_CHECK_EQUAL(center->getEnergy(),highNeighbors);
            center->setValue(1);
            BOOST_CHECK_EQUAL(center->getEnergy(),neighbors.size()-highNeighbors);
        }
    }
}

BOOST_AUTO_TEST_CASE( testSpecificEnergy ) {
    Cell &center = *grid[5];
    Cell::Neighbors neighbors = center.getNeighbors();
    center.setValue(1);
    neighbors[0]->setValue(0);
    neighbors[1]->setValue(1);
    neighbors[2]->setValue(1);
    neighbors[3]->setValue(1);
}

BOOST_AUTO_TEST_CASE( testSubsetsAreDifferentKinds ) {
    BOOST_REQUIRE(grid.odds.getKind()!=grid.evens.getKind());
}

BOOST_AUTO_TEST_CASE( testDifferentSubsetBeginning ) {
    BOOST_REQUIRE(grid.odds.begin()!=grid.evens.begin());
}

BOOST_AUTO_TEST_SUITE_END() <commit_msg>Test the energy after Cell::toggle.<commit_after>//
//  IsingGridTest.cpp
//  jdemon
//
//  Created by Mark Larus on 3/11/13.
//  Copyright (c) 2013 Kenyon College. All rights reserved.
//

#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
#include <algorithm>
#include <set>
#include <sstream>
#include <map>

#include "IsingGrid.h"

using namespace boost::unit_test;
using namespace Ising;
typedef std::set<Ising::Cell*> CellSet;

struct EvenIsingGridFixture {
    Ising::Grid grid;
    EvenIsingGridFixture() : grid(6) {}
};

BOOST_FIXTURE_TEST_SUITE(IsingGridTest, EvenIsingGridFixture)

BOOST_AUTO_TEST_CASE( oddGridInvalid ) {
    BOOST_REQUIRE_THROW(Grid k(3), InvalidGridSize);
}

BOOST_AUTO_TEST_CASE( tooSmallGrid ) {
    BOOST_REQUIRE_THROW(Grid k(2), InvalidGridSize);
}

BOOST_AUTO_TEST_CASE( testEvenOddIteratorsDisjoint__evenGrid ) {
    BOOST_REQUIRE_EQUAL(grid.getDimension()%2, 0);
    CellSet evenSet;
    evenSet.insert(grid.evens.begin(),grid.evens.end());
    CellSet oddSet;
    oddSet.insert(grid.odds.begin(),grid.odds.end());
    size_t count = 0;

    for (CellSet::iterator it = evenSet.begin(); it!=evenSet.end(); ++it) {
        BOOST_CHECK(!oddSet.count(*it));
        ++count;
        BOOST_REQUIRE_LE(count, grid.size());
    }
    count = 0;
    for (CellSet::iterator it = oddSet.begin(); it!=oddSet.end(); ++it) {
        BOOST_CHECK(!evenSet.count(*it));
        ++count;
        BOOST_REQUIRE_LE(count, grid.size());
    }
}

BOOST_AUTO_TEST_CASE( testEvenCellsCount ) {
    int count = 0;
    for (Grid::subset::iterator it = grid.evens.begin(); it!=grid.evens.end(); ++it) {
        ++count;
        // Infinite loop protection.
        BOOST_REQUIRE_LE(count, grid.size());
    }
    BOOST_REQUIRE_EQUAL(count,grid.size()/2);
}

BOOST_AUTO_TEST_CASE( testOddCellsCount ) {
    int count = 0;
    for (Grid::subset::iterator it = grid.odds.begin(); it!=grid.odds.end(); ++it) {
        ++count;
        // Infinite loop protection:
        BOOST_REQUIRE_LE(count, grid.size());
    }
    BOOST_REQUIRE_EQUAL(count,grid.size()/2);
}

BOOST_AUTO_TEST_CASE( testAllCellsCount ) {
    int count = 0;
    for (Grid::iterator it = grid.begin(); it!=grid.end(); ++it) {
        ++count;
        // Infinite loop protection:
        BOOST_REQUIRE_LE(count, grid.size());
    }
    BOOST_REQUIRE_EQUAL(count, grid.size());
}

BOOST_AUTO_TEST_CASE( testAllCellsInEvenOdd ) {
    CellSet evenOddSet, allSet;
    evenOddSet.insert(grid.evens.begin(), grid.evens.end());
    evenOddSet.insert(grid.odds.begin(),grid.odds.end());
    allSet.insert(grid.begin(),grid.end());

    for (CellSet::iterator it = allSet.begin(); it!=allSet.end(); ++it) {
        BOOST_CHECK(evenOddSet.count(*it));
    }

    for (CellSet::iterator it = evenOddSet.begin(); it!=evenOddSet.end(); ++it) {
        BOOST_CHECK(allSet.count(*it));
    }
}

BOOST_AUTO_TEST_CASE( testUniqueNeighbors ) {
    size_t loops = 0;
    for(Grid::iterator it = grid.begin(); it!=grid.end(); ++it) {
        Cell::Neighbors neighbors = (*it)->getNeighbors();
        CellSet neighborSet(neighbors.begin(),neighbors.end());

        BOOST_CHECK_EQUAL(neighborSet.size(), neighbors.size());

        // I wouldn't consider this an important unit test
        // But we might want to know if this changed:
        BOOST_CHECK_EQUAL(neighbors.size(), 4);
        BOOST_REQUIRE_LE(loops, grid.size());
    }
}

BOOST_AUTO_TEST_CASE( testNeighborsRelation_evenGrid ) {
    CellSet evenNeighbors, evenCells;
    CellSet oddNeighbors, oddCells;
    size_t loopGuard = 0;
    for (Grid::subset::iterator it = grid.evens.begin(); it!=grid.evens.end(); ++it) {
        ++loopGuard;
        evenCells.insert(*it);
        Cell::Neighbors neighbors = (*it)->getNeighbors();
        evenNeighbors.insert(neighbors.begin(),neighbors.end());
        BOOST_REQUIRE_LE(loopGuard, grid.size());
    }
    CellSet evenIntersection;
    std::insert_iterator<CellSet> insertionIterator(evenIntersection,evenIntersection.end());
    std::set_intersection(evenNeighbors.begin(), evenNeighbors.end(), evenCells.begin(), evenCells.end(), insertionIterator);

    BOOST_CHECK(evenIntersection.empty());

    BOOST_CHECK(!oddNeighbors.count(*grid.begin()));

    loopGuard = 0;
    for (Grid::subset::iterator it = grid.odds.begin(); it != grid.odds.end(); ++it) {
        ++loopGuard;
        oddCells.insert(*it);
        Cell::Neighbors neighbors = (*it)->getNeighbors();
        oddNeighbors.insert(neighbors.begin(),neighbors.end());
        BOOST_REQUIRE_LE(loopGuard, grid.size());
    }
    CellSet oddIntersection;
    std::insert_iterator<CellSet> oddInsertionIterator(evenIntersection,evenIntersection.end());
    std::set_intersection(oddNeighbors.begin(), oddNeighbors.end(), oddCells.begin(), oddCells.end(), oddInsertionIterator);
    BOOST_CHECK(oddIntersection.empty());

    BOOST_CHECK_EQUAL_COLLECTIONS(evenNeighbors.begin(), evenNeighbors.end(), oddCells.begin(), oddCells.end());
    BOOST_CHECK_EQUAL_COLLECTIONS(oddNeighbors.begin(), oddNeighbors.end(), evenCells.begin(), evenCells.end());
}

BOOST_AUTO_TEST_CASE( gridSize ) {
    BOOST_REQUIRE_EQUAL(grid.size(),grid.getDimension()*grid.getDimension());
}

BOOST_AUTO_TEST_CASE( testGetDimension ) {
    Grid grid(10);
    BOOST_REQUIRE_EQUAL(grid.getDimension(),10);
}

BOOST_AUTO_TEST_CASE( testNeighborsTransitive ) {
    size_t loops = 0;
    for(Grid::iterator it = grid.begin(); it!=grid.end(); ++it) {
        size_t innerLoops = 0;
        Cell::Neighbors neighbors = (*it)->getNeighbors();
        for (Cell::Neighbors::iterator neighbor = neighbors.begin(); neighbor!=neighbors.end(); ++neighbor) {
            Cell::Neighbors reverseNeighbors = (*neighbor)->getNeighbors();
            long count = std::count(reverseNeighbors.begin(), reverseNeighbors.end(), *it);
            BOOST_CHECK_EQUAL(count, 1);
            BOOST_REQUIRE_LE(innerLoops, neighbors.size());
            ++innerLoops;
        }
        ++loops;
        BOOST_REQUIRE_LE(loops, grid.size());
    }
}

BOOST_AUTO_TEST_CASE( testSetValue ) {
    Cell &cell = *grid[5];
    cell.setValue(0);
    BOOST_CHECK_EQUAL(cell.getValue(), 0);
    cell.setValue(1);
    BOOST_CHECK_EQUAL(cell.getValue(), 1);
    BOOST_REQUIRE_THROW(cell.setValue(2), InvalidCellValue);
    BOOST_REQUIRE_THROW(cell.setValue(-1), InvalidCellValue);
}

BOOST_AUTO_TEST_CASE( testRandomAccess ) {
    // The only interface contract here is that different grid indexes
    // return different cell pointers, and that an invalid index throws.
    CellSet cells;
    size_t size = grid.size();
    for (size_t k = 0; k != grid.size(); ++k) {
        cells.insert(grid[k]);
    }
    BOOST_REQUIRE(cells.size()==size);
    BOOST_REQUIRE_THROW(grid[2*size], InvalidGridIndex);
}

BOOST_AUTO_TEST_CASE( testEnergy ) {
    BOOST_FOREACH(Cell *center, std::make_pair(grid.begin(),grid.end())) {
        Cell::Neighbors neighbors = center->getNeighbors();
        for (int k = 0; k != (1 << neighbors.size()); ++k) {
            int highNeighbors = 0;
            for(int neighbor = 0; neighbor < neighbors.size(); ++neighbor) {
                int value = (k >> neighbor) & 1;
                highNeighbors += value;
                neighbors[neighbor]->setValue(value);
            }
            center->setValue(0);
            BOOST_CHECK_EQUAL(center->getEnergy(),highNeighbors);
            center->setValue(1);
            BOOST_CHECK_EQUAL(center->getEnergy(),neighbors.size()-highNeighbors);
        }
    }
}

BOOST_AUTO_TEST_CASE( testSpecificEnergy ) {
    Cell &center = *grid[5];
    Cell::Neighbors neighbors = center.getNeighbors();
    center.setValue(1);
    neighbors[0]->setValue(0);
    neighbors[1]->setValue(1);
    neighbors[2]->setValue(1);
    neighbors[3]->setValue(1);
}

BOOST_AUTO_TEST_CASE( testSubsetsAreDifferentKinds ) {
    BOOST_REQUIRE(grid.odds.getKind()!=grid.evens.getKind());
}

BOOST_AUTO_TEST_CASE( testDifferentSubsetBeginning ) {
    BOOST_REQUIRE(grid.odds.begin()!=grid.evens.begin());
}

BOOST_AUTO_TEST_CASE( testToggleEnergy ) {
    Cell &cell = *grid[5];
    long energy = cell.getEnergy();
    cell.toggle();
    BOOST_REQUIRE_EQUAL(cell.getEnergy(),cell.getNeighbors().size()-energy);
}

BOOST_AUTO_TEST_SUITE_END() <|endoftext|>


<commit_before>#include "usb.h"
#include "OpenFocus.h"

#define USB_RQ_REBOOT 0x01
#define USB_RQ_WRITE_FLASH_BLOCK 0x02
#define USB_RQ_GET_REPORT 0x03
#define USB_RQ_WRITE_EEPROM_BLOCK 0x04
#define USB_RQ_READ_EEPROM_BLOCK 0x05

unsigned short OpenFocus::Bootloader::Vendor_ID = 0x20a0;
unsigned short OpenFocus::Bootloader::Product_ID = 0x416d;

struct usb_dev_handle *OpenFocus::Bootloader::device = NULL;

OpenFocus::Bootloader::Bootloader()
{
    device = NULL;
}

bool OpenFocus::Bootloader::Connect()
{
    if (!usb_open_device(&device, Vendor_ID, Product_ID))
        return false;

    unsigned char *data = (unsigned char *)malloc(sizeof(unsigned char) * 8);
    GetReport(data);

    if (data == NULL)
        return false;

    PageSize = (unsigned short)((data[1] << 8) | data[0]);
    FlashSize = (unsigned short)((data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2]);
    EEPROMSize = (unsigned short)((data[7] << 8) | data[6]);

    free(data);

    return true;
}

void OpenFocus::Bootloader::Disconnect()
{
    if (device)
        usb_close(device);
    device = NULL;
}

int OpenFocus::Bootloader::Reboot()
{
    return usb_control_msg(device, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_RQ_REBOOT, 0, 0, NULL, 0, 5000);
}

int OpenFocus::Bootloader::GetReport(unsigned char *data)
{
    return usb_control_msg(device, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USB_RQ_GET_REPORT, 0, 0, (char *)data, 8, 5000);
}

int OpenFocus::Bootloader::WriteEepromBlock(unsigned short address, char *data, int length)
{
    data = (char *)realloc(data, length + sizeof(address));
    memmove((void *)(data+2), data, length);
    memcpy(data, ToUsbInt(address, sizeof(address)), sizeof(address));

    return usb_control_msg(device, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_RQ_WRITE_EEPROM_BLOCK, 0, 0, data, length + sizeof(address), 5000);
}

int OpenFocus::Bootloader::WriteEeprom(char *data, int length)
{
    unsigned short blocksize = 2;
    for (unsigned short address = 0; address < length; address += blocksize) {
        if ((address + blocksize) > length)
            blocksize = length - address;
        if (WriteEepromBlock(address, data, blocksize) != 0)
            return -1;
        data += blocksize;
    }
    free(data);
    return 0;
}

int OpenFocus::Bootloader::WriteFlashBlock(unsigned short address, char *data, int length)
{
    data = (char *)realloc(data, length + sizeof(address));                 /* Reallocate extra space for address */
    memmove((void *)(data+2), data, length);                                /* Move the data 2 bytes forward */
    memcpy(data, ToUsbInt(address, sizeof(address)), sizeof(address));      /* Copy the address into the first 2 bytes */

    return usb_control_msg(device, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_RQ_WRITE_FLASH_BLOCK, 0, 0, data, length + sizeof(address), 5000);
}

int OpenFocus::Bootloader::WriteFlash(char *data, int length)
{
    for (unsigned short address = 0; address < length; address += PageSize) {
        if (WriteFlashBlock(address, data, PageSize) != 0)
            return -1;
        data += PageSize;
    }
    free(data);
    return 0;
}

unsigned char* OpenFocus::Bootloader::ToUsbInt(unsigned int value, int length)
{
    unsigned char *bytes = (unsigned char *)malloc(sizeof(unsigned char) * length);

    for (int i = 0; i < length; i++)
    {
        bytes[i] = (unsigned char)(value & 0xff);
        value >>= 8;
    }

    return bytes;
}

unsigned int OpenFocus::Bootloader::GetUsbInt(unsigned char *bytes, int length)
{
    unsigned int value = 0;
    int shift = 0;

    for (int i = 0; i < length; i++)
    {
        value |= (unsigned int)(bytes[i] << shift);
        shift += 8;
    }

    return value;
}

<commit_msg>block type.<commit_after>#include "usb.h"
#include "OpenFocus.h"

#define USB_RQ_REBOOT 0x01
#define USB_RQ_WRITE_FLASH_BLOCK 0x02
#define USB_RQ_GET_REPORT 0x03
#define USB_RQ_WRITE_EEPROM_BLOCK 0x04
#define USB_RQ_READ_EEPROM_BLOCK 0x05

unsigned short OpenFocus::Bootloader::Vendor_ID = 0x20a0;
unsigned short OpenFocus::Bootloader::Product_ID = 0x416d;

struct usb_dev_handle *OpenFocus::Bootloader::device = NULL;

/* Type that is used to send a block of data for eeprom or flash writing */
typedef union block {
    struct {
        unsigned short address;
        char data;
    };
    char bytes;
} block;

/* Swaps byte positions in a short */
static inline unsigned short endian_swap(unsigned short val)
{
    return ((val & 0xff) << 8) | ((val >> 8) & 0xff);
}

OpenFocus::Bootloader::Bootloader()
{
    device = NULL;
}

bool OpenFocus::Bootloader::Connect()
{
    if (!usb_open_device(&device, Vendor_ID, Product_ID))
        return false;

    unsigned char *data = (unsigned char *)malloc(sizeof(unsigned char) * 8);
    GetReport(data);

    if (data == NULL)
        return false;

    PageSize = (unsigned short)((data[1] << 8) | data[0]);
    FlashSize = (unsigned short)((data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2]);
    EEPROMSize = (unsigned short)((data[7] << 8) | data[6]);

    free(data);

    return true;
}

void OpenFocus::Bootloader::Disconnect()
{
    if (device)
        usb_close(device);
    device = NULL;
}

int OpenFocus::Bootloader::Reboot()
{
    return usb_control_msg(device, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_RQ_REBOOT, 0, 0, NULL, 0, 5000);
}

int OpenFocus::Bootloader::GetReport(unsigned char *data)
{
    return usb_control_msg(device, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USB_RQ_GET_REPORT, 0, 0, (char *)data, 8, 5000);
}

int OpenFocus::Bootloader::WriteEepromBlock(unsigned short address, char *data, int length)
{
    block *b = (block *)malloc(length + sizeof(address));
    b->address = endian_swap(address);
    memcpy(&b->data, data, length);

    int retval = usb_control_msg(device, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_RQ_WRITE_EEPROM_BLOCK, 0, 0, &b->bytes, length + sizeof(address), 5000);

    free(b);

    return retval;
}

int OpenFocus::Bootloader::WriteEeprom(char *data, int length)
{
    unsigned short blocksize = 2;
    for (unsigned short address = 0; address < length; address += blocksize) {
        if ((address + blocksize) > length)
            blocksize = length - address;
        if (WriteEepromBlock(address, data, blocksize) != 0)
            return -1;
        data += blocksize;
    }
    return 0;
}

int OpenFocus::Bootloader::WriteFlashBlock(unsigned short address, char *data, int length)
{
    block *b = (block *)malloc(length + sizeof(address));
    b->address = endian_swap(address);
    memcpy(&b->data, data, length);

    int retval = usb_control_msg(device, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_RQ_WRITE_FLASH_BLOCK, 0, 0, &b->bytes, length + sizeof(address), 5000);

    free(b);

    return retval;
}

int OpenFocus::Bootloader::WriteFlash(char *data, int length)
{
    for (unsigned short address = 0; address < length; address += PageSize) {
        if (WriteFlashBlock(address, data, PageSize) != 0)
            return -1;
        data += PageSize;
    }
    return 0;
}

unsigned char* OpenFocus::Bootloader::ToUsbInt(unsigned int value, int length)
{
    unsigned char *bytes = (unsigned char *)malloc(sizeof(unsigned char) * length);

    for (int i = 0; i < length; i++)
    {
        bytes[i] = (unsigned char)(value & 0xff);
        value >>= 8;
    }

    return bytes;
}

unsigned int OpenFocus::Bootloader::GetUsbInt(unsigned char *bytes, int length)
{
    unsigned int value = 0;
    int shift = 0;

    for (int i = 0; i < length; i++)
    {
        value |= (unsigned int)(bytes[i] << shift);
        shift += 8;
    }

    return value;
}

<|endoftext|>