text:
// ------------------------------------------------------------------
// pion-net: a C++ framework for building lightweight HTTP interfaces
// ------------------------------------------------------------------
// Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//

#include <pion/PionConfig.hpp>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/scoped_array.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/filesystem.hpp>
#include <pion/PionPlugin.hpp>
#include <pion/PionScheduler.hpp>
#include <pion/net/HTTPRequest.hpp>
#include <pion/net/HTTPResponse.hpp>
#include <pion/net/HTTPRequestWriter.hpp>
#include <pion/net/HTTPResponseReader.hpp>
#include <pion/net/WebServer.hpp>
#include <pion/net/PionUser.hpp>
#include <pion/net/HTTPBasicAuth.hpp>
#include <pion/net/HTTPCookieAuth.hpp>

using namespace std;
using namespace pion;
using namespace pion::net;
using boost::asio::ip::tcp;

PION_DECLARE_PLUGIN(EchoService)
PION_DECLARE_PLUGIN(FileService)
PION_DECLARE_PLUGIN(HelloService)
PION_DECLARE_PLUGIN(LogService)
PION_DECLARE_PLUGIN(CookieService)

#if defined(PION_XCODE)
	static const std::string PATH_TO_PLUGINS(".");
	static const std::string SSL_PEM_FILE("../../utils/sslkey.pem");
	static const std::string SERVICES_CONFIG_FILE("../tests/config/testservices.conf");
#else
	// same for Unix and Windows
	static const std::string PATH_TO_PLUGINS("../services/.libs");
	static const std::string SSL_PEM_FILE("../utils/sslkey.pem");
	static const std::string SERVICES_CONFIG_FILE("../tests/config/testservices.conf");
#endif

/// generates chunked POST requests for testing purposes
class ChunkedPostRequestSender :
	public boost::enable_shared_from_this<ChunkedPostRequestSender>,
	private boost::noncopyable
{
public:
	/**
	 * creates new ChunkedPostRequestSender objects
	 *
	 * @param tcp_conn TCP connection used to send the file
	 * @param resource
	 */
	static inline boost::shared_ptr<ChunkedPostRequestSender>
		create(pion::net::TCPConnectionPtr& tcp_conn, const std::string& resource)
	{
		return boost::shared_ptr<ChunkedPostRequestSender>(new ChunkedPostRequestSender(tcp_conn, resource));
	}

	~ChunkedPostRequestSender() {
		for (m_chunk_iterator = m_chunks.begin(); m_chunk_iterator != m_chunks.end(); ++m_chunk_iterator) {
			delete[] m_chunk_iterator->second;
		}
	}

	void send(void);

	void addChunk(size_t size, const char* ptr) {
		char* localCopy = new char[size];
		memcpy(localCopy, ptr, size);
		m_chunks.push_back(Chunk(size, localCopy));
		m_chunk_iterator = m_chunks.begin();
	}

protected:

	ChunkedPostRequestSender(pion::net::TCPConnectionPtr& tcp_conn,
							 const std::string& resource);

	/**
	 * handler called after a send operation has completed
	 *
	 * @param write_error error status from the last write operation
	 * @param bytes_written number of bytes sent by the last write operation
	 */
	void handleWrite(const boost::system::error_code& write_error,
					 std::size_t bytes_written);

private:

	typedef std::pair<size_t, char*> Chunk;

	/// primary logging interface used by this class
	pion::PionLogger						m_logger;

	/// the chunks we are sending
	std::vector<Chunk>						m_chunks;

	std::vector<Chunk>::const_iterator		m_chunk_iterator;

	/// the HTTP request writer we are using
	pion::net::HTTPRequestWriterPtr			m_writer;
};

ChunkedPostRequestSender::ChunkedPostRequestSender(pion::net::TCPConnectionPtr& tcp_conn,
												   const std::string& resource)
	: m_logger(PION_GET_LOGGER("pion.ChunkedPostRequestSender")),
	m_writer(pion::net::HTTPRequestWriter::create(tcp_conn))
{
	m_writer->getRequest().setMethod("POST");
	m_writer->getRequest().setResource(resource);
	m_writer->getRequest().setChunksSupported(true);
	m_chunk_iterator = m_chunks.begin();
}

void ChunkedPostRequestSender::send(void)
{
	if (m_chunk_iterator == m_chunks.end()) {
		m_writer->sendFinalChunk(boost::bind(&ChunkedPostRequestSender::handleWrite,
											 shared_from_this(),
											 boost::asio::placeholders::error,
											 boost::asio::placeholders::bytes_transferred));
		return;
	}

	// write the current chunk
	m_writer->writeNoCopy(m_chunk_iterator->second, m_chunk_iterator->first);

	if (++m_chunk_iterator == m_chunks.end()) {
		m_writer->sendFinalChunk(boost::bind(&ChunkedPostRequestSender::handleWrite,
											 shared_from_this(),
											 boost::asio::placeholders::error,
											 boost::asio::placeholders::bytes_transferred));
	} else {
		m_writer->sendChunk(boost::bind(&ChunkedPostRequestSender::handleWrite,
										shared_from_this(),
										boost::asio::placeholders::error,
										boost::asio::placeholders::bytes_transferred));
	}
}

void ChunkedPostRequestSender::handleWrite(const boost::system::error_code& write_error,
										   std::size_t bytes_written)
{
	if (write_error) {
		// encountered error sending request data
		m_writer->getTCPConnection()->setLifecycle(TCPConnection::LIFECYCLE_CLOSE);	// make sure it will get closed
		PION_LOG_ERROR(m_logger, "Error sending chunked request (" << write_error.message() << ')');
	} else {
		// request data sent OK

		if (m_chunk_iterator == m_chunks.end()) {
			PION_LOG_DEBUG(m_logger, "Sent " << bytes_written << " bytes (finished)");
		} else {
			PION_LOG_DEBUG(m_logger, "Sent " << bytes_written << " bytes");
			m_writer->clear();
			send();
		}
	}
}

///
/// WebServerTests_F: fixture used for running web server tests
///
class WebServerTests_F {
public:

	// default constructor & destructor
	WebServerTests_F() : m_scheduler(), m_server(m_scheduler) {
		// initialize the list of directories in which to look for plug-ins
		PionPlugin::resetPluginDirectories();
#ifndef PION_STATIC_LINKING
		PionPlugin::addPluginDirectory(PATH_TO_PLUGINS);
#endif
	}
	~WebServerTests_F() {
		m_server.stop();
		m_scheduler.shutdown();
	}

	/**
	 * sends a request to the local HTTP server
	 *
	 * @param http_stream open stream to send the request via
	 * @param resource name of the HTTP resource to request
	 * @param content_length bytes available in the response, if successful
	 */
	inline unsigned int sendRequest(tcp::iostream& http_stream,
									const std::string& resource,
									unsigned long& content_length)
	{
		const boost::regex regex_get_response_code("^HTTP/1\\.1\\s(\\d+)\\s.*");
		const boost::regex regex_response_header("^[A-Za-z0-9_-]+:\\s.*");
		const boost::regex regex_content_length_header("^Content-Length:\\s(\\d+).*", boost::regex::icase);
		const boost::regex regex_response_end("^\\s*$");

		// send HTTP request to the server
		http_stream << "GET " << resource << " HTTP/1.1" << HTTPTypes::STRING_CRLF << HTTPTypes::STRING_CRLF;
		http_stream.flush();

		// receive response from the server
		std::string rsp_line;
		boost::smatch rx_matches;
		unsigned int response_code = 0;
		BOOST_REQUIRE(std::getline(http_stream, rsp_line));
		BOOST_REQUIRE(boost::regex_match(rsp_line, rx_matches, regex_get_response_code));
		BOOST_REQUIRE(rx_matches.size() == 2);

		// extract response status code
		response_code = boost::lexical_cast<unsigned int>(rx_matches[1]);
		BOOST_REQUIRE(response_code != 0);

		// read response headers
		content_length = 0;
		while (true) {
			BOOST_REQUIRE(std::getline(http_stream, rsp_line));
			// check for end of response headers (empty line)
			if (boost::regex_match(rsp_line, rx_matches, regex_response_end))
				break;
			// check validity of response header
			BOOST_REQUIRE(boost::regex_match(rsp_line, rx_matches, regex_response_header));
			// check for content-length response header
			if (boost::regex_match(rsp_line, rx_matches, regex_content_length_header)) {
				if (rx_matches.size() == 2)
					content_length = boost::lexical_cast<unsigned long>(rx_matches[1]);
			}
		}

		return response_code;
	}

	/**
	 * checks the local HTTP server's response code & validity using HelloService
	 */
	inline void checkWebServerResponseCode(void) {
		// load simple Hello service and start the server
		m_server.loadService("/hello", "HelloService");
		m_server.start();

		// open a connection
		tcp::endpoint http_endpoint(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
		tcp::iostream http_stream(http_endpoint);

		// send valid request to the server
		unsigned int response_code;
		unsigned long content_length = 0;
		response_code = sendRequest(http_stream, "/hello", content_length);
		BOOST_CHECK(response_code == 200);
		BOOST_CHECK(content_length > 0);
		if (content_length > 0) {
			boost::scoped_array<char> content_buf(new char[content_length+1]);
			BOOST_CHECK(http_stream.read(content_buf.get(), content_length));
		}

		// send invalid request to the server
		response_code = sendRequest(http_stream, "/doesnotexist", content_length);
		BOOST_CHECK(response_code == 404);
	}

	/**
	 * checks response content validity for the local HTTP server
	 *
	 * @param http_stream open stream to send the request via
	 * @param resource name of the HTTP resource to request
	 * @param content_regex regex that the response content should match
	 */
	inline void checkWebServerResponseContent(tcp::iostream& http_stream,
											  const std::string& resource,
											  const boost::regex& content_regex,
											  unsigned int expectedResponseCode = 200)
	{
		// send valid request to the server
		unsigned int response_code;
		unsigned long content_length = 0;
		response_code = sendRequest(http_stream, resource, content_length);
		BOOST_CHECK(response_code == expectedResponseCode);
		BOOST_REQUIRE(content_length > 0);

		// read in the response content
		boost::scoped_array<char> content_buf(new char[content_length+1]);
		BOOST_CHECK(http_stream.read(content_buf.get(), content_length));
		content_buf[content_length] = '\0';

		// check the response content
		BOOST_CHECK(boost::regex_match(content_buf.get(), content_regex));
	}

	/**
	 * checks response content validity for the local HTTP server
	 *
	 * @param service name of the web service to load and query
	 * @param resource name of the HTTP resource to request
	 * @param content_regex regex that the response content should match
	 */
	inline void checkWebServerResponseContent(const std::string& service,
											  const std::string& resource,
											  const boost::regex& content_regex,
											  unsigned int expectedResponseCode = 200)
	{
		// load specified service and start the server
		m_server.loadService(resource, service);
		m_server.start();

		// open a connection
		tcp::endpoint http_endpoint(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
		tcp::iostream http_stream(http_endpoint);

		// send request and check response
		checkWebServerResponseContent(http_stream, resource, content_regex, expectedResponseCode);
	}

	/**
	 * checks if we can successfully send and receive HTTP messages
	 *
	 * @param tcp_conn open TCP connection to use for the tests
	 */
	inline void checkSendAndReceiveMessages(TCPConnection& tcp_conn) {
		// send valid request to the server
		HTTPRequest http_request("/hello");
		boost::system::error_code error_code;
		http_request.send(tcp_conn, error_code);
		BOOST_REQUIRE(! error_code);

		// receive the response from the server
		HTTPResponse http_response(http_request);
		http_response.receive(tcp_conn, error_code);
		BOOST_REQUIRE(! error_code);

		// check that the response is OK
		boost::regex hello_regex(".*Hello\\sWorld.*");
		BOOST_REQUIRE(http_response.getStatusCode() == 200);
		BOOST_REQUIRE(http_response.getContentLength() > 0);
		BOOST_REQUIRE(boost::regex_match(http_response.getContent(), hello_regex));

		// send invalid request to the server
		http_request.setResource("/doesnotexist");
		http_request.send(tcp_conn, error_code);
		BOOST_REQUIRE(! error_code);
		http_response.receive(tcp_conn, error_code);
		BOOST_REQUIRE(! error_code);
		BOOST_CHECK_EQUAL(http_response.getStatusCode(), 404U);
	}

	inline boost::asio::io_service& getIOService(void) { return m_scheduler.getIOService(); }

	PionSingleServiceScheduler	m_scheduler;
	WebServer					m_server;
};

// WebServer Test Cases

BOOST_FIXTURE_TEST_SUITE(WebServerTests_S, WebServerTests_F)

BOOST_AUTO_TEST_CASE(checkWebServerIsListening) {
	BOOST_CHECK(! m_server.isListening());
	m_server.start();
	BOOST_CHECK(m_server.isListening());
	m_server.stop();
	BOOST_CHECK(! m_server.isListening());
}

BOOST_AUTO_TEST_CASE(checkWebServerRespondsProperly) {
	checkWebServerResponseCode();
}

BOOST_AUTO_TEST_CASE(checkSendRequestsAndReceiveResponses) {
	// load simple Hello service and start the server
	m_server.loadService("/hello", "HelloService");
	m_server.start();

	// open a connection
	TCPConnection tcp_conn(getIOService());
	tcp_conn.setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn.connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(! error_code);

	checkSendAndReceiveMessages(tcp_conn);
}

BOOST_AUTO_TEST_CASE(checkSendRequestAndReceiveResponseFromEchoService) {
	m_server.loadService("/echo", "EchoService");
	m_server.start();

	// open a connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	HTTPRequestWriterPtr writer(HTTPRequestWriter::create(tcp_conn));
	writer->getRequest().setMethod("POST");
	writer->getRequest().setResource("/echo");

	writer << "junk";
	writer->send();

	// receive the response from the server
	HTTPResponse http_response(writer->getRequest());
	http_response.receive(*tcp_conn, error_code);
	BOOST_CHECK(!error_code);

	// check that the response is OK
	BOOST_CHECK(http_response.getStatusCode() == 200);
	BOOST_CHECK(http_response.getContentLength() > 0);

	// check the post content of the request, by parsing it out of the post content of the response
	boost::regex post_content(".*\\[POST Content]\\s*junk.*");
	BOOST_CHECK(boost::regex_match(http_response.getContent(), post_content));
}

BOOST_AUTO_TEST_CASE(checkRedirectHelloServiceToEchoService) {
	m_server.loadService("/hello", "HelloService");
	m_server.loadService("/echo", "EchoService");
	m_server.start();

	// open a connection
	tcp::endpoint http_endpoint(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	tcp::iostream http_stream(http_endpoint);

	// send a request to /hello and check that the response is from HelloService
	checkWebServerResponseContent(http_stream, "/hello", boost::regex(".*Hello\\sWorld.*"));

	m_server.addRedirect("/hello", "/echo");

	// send a request to /hello and check that the response is from EchoService
	checkWebServerResponseContent(http_stream, "/hello", boost::regex(".*\\[Request\\sEcho\\].*"));
}

BOOST_AUTO_TEST_CASE(checkOriginalResourceAvailableAfterRedirect) {
	m_server.loadService("/hello", "HelloService");
	m_server.loadService("/echo", "EchoService");
	m_server.start();

	// open a connection
	tcp::endpoint http_endpoint(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	tcp::iostream http_stream(http_endpoint);

	m_server.addRedirect("/hello", "/echo");

	// send a request to /hello and check the reported values of the original resource and the delivered resource
	boost::regex regex_expected_content(".*Resource\\soriginally\\srequested:\\s/hello.*Resource\\sdelivered:\\s/echo.*");
	checkWebServerResponseContent(http_stream, "/hello", regex_expected_content);
}

BOOST_AUTO_TEST_CASE(checkRecursiveRedirect) {
	m_server.loadService("/hello", "HelloService");
	m_server.loadService("/echo", "EchoService");
	m_server.loadService("/cookie", "CookieService");
	m_server.start();

	// open a connection
	tcp::endpoint http_endpoint(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	tcp::iostream http_stream(http_endpoint);

	m_server.addRedirect("/hello", "/echo");
	m_server.addRedirect("/echo", "/cookie");

	// send a request to /hello and check that the response is from CookieService
	checkWebServerResponseContent(http_stream, "/hello", boost::regex(".*<html>.*Cookie\\sService.*</html>.*"));
}

BOOST_AUTO_TEST_CASE(checkCircularRedirect) {
	m_server.loadService("/hello", "HelloService");
	m_server.loadService("/cookie", "CookieService");
	m_server.loadService("/echo", "EchoService");
	m_server.start();

	// open a connection
	tcp::endpoint http_endpoint(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	tcp::iostream http_stream(http_endpoint);

	// set up a circular set of redirects
	m_server.addRedirect("/hello", "/echo");
	m_server.addRedirect("/echo", "/cookie");
	m_server.addRedirect("/cookie", "/hello");

	// send request and check that server returns expected status code and error message
	checkWebServerResponseContent(http_stream, "/hello",
								  boost::regex(".*Maximum number of redirects.*exceeded.*"),
								  HTTPTypes::RESPONSE_CODE_SERVER_ERROR);
}

BOOST_AUTO_TEST_CASE(checkSendChunkedRequestAndReceiveResponse) {
	m_server.loadService("/echo", "EchoService");
	m_server.start();

	// open a connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	boost::shared_ptr<ChunkedPostRequestSender> sender = ChunkedPostRequestSender::create(tcp_conn, "/echo");
	sender->addChunk(5, "klmno");
	sender->addChunk(4, "1234");
	sender->addChunk(10, "abcdefghij");
	sender->send();

	// receive the response from the server
	HTTPResponse http_response("GET");
	http_response.receive(*tcp_conn, error_code);
	BOOST_CHECK(!error_code);

	// check that the response is OK
	BOOST_CHECK(http_response.getStatusCode() == 200);
	BOOST_CHECK(http_response.getContentLength() > 0);

	// check the content length of the request, by parsing it out of the post content of the response
	boost::regex content_length_of_request(".*Content length\\: 19.*");
	BOOST_CHECK(boost::regex_match(http_response.getContent(), content_length_of_request));

	// check the post content of the request, by parsing it out of the post content of the response
	boost::regex post_content_of_request(".*\\[POST Content]\\s*klmno1234abcdefghij.*");
	BOOST_CHECK(boost::regex_match(http_response.getContent(), post_content_of_request));
}

BOOST_AUTO_TEST_CASE(checkSendChunkedRequestWithOneChunkAndReceiveResponse) {
	m_server.loadService("/echo", "EchoService");
	m_server.start();

	// open a connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	boost::shared_ptr<ChunkedPostRequestSender> sender = ChunkedPostRequestSender::create(tcp_conn, "/echo");
	sender->addChunk(10, "abcdefghij");
	sender->send();

	// receive the response from the server
	HTTPResponse http_response("GET");
	http_response.receive(*tcp_conn, error_code);
	BOOST_CHECK(!error_code);

	// check that the response is OK
	BOOST_CHECK(http_response.getStatusCode() == 200);
	BOOST_CHECK(http_response.getContentLength() > 0);

	// check the post content of the request, by parsing it out of the post content of the response
	boost::regex post_content(".*\\[POST Content]\\s*abcdefghij.*");
	BOOST_CHECK(boost::regex_match(http_response.getContent(), post_content));
}

BOOST_AUTO_TEST_CASE(checkSendChunkedRequestWithNoChunksAndReceiveResponse) {
	m_server.loadService("/echo", "EchoService");
	m_server.start();

	// open a connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	boost::shared_ptr<ChunkedPostRequestSender> sender = ChunkedPostRequestSender::create(tcp_conn, "/echo");
	sender->send();

	// receive the response from the server
	HTTPResponse http_response("GET");
	http_response.receive(*tcp_conn, error_code);
	BOOST_CHECK(!error_code);

	// check that the response is OK
	BOOST_CHECK(http_response.getStatusCode() == 200);
	BOOST_CHECK(http_response.getContentLength() > 0);

	// check the content length of the request, by parsing it out of the post content of the response
	boost::regex content_length_of_request(".*Content length\\: 0.*");
	BOOST_CHECK(boost::regex_match(http_response.getContent(), content_length_of_request));
}

#ifdef PION_HAVE_SSL
BOOST_AUTO_TEST_CASE(checkSendRequestsAndReceiveResponsesUsingSSL) {
	// load simple Hello service and start the server
	m_server.setSSLKeyFile(SSL_PEM_FILE);
	m_server.loadService("/hello", "HelloService");
	m_server.start();

	// open a connection
	TCPConnection tcp_conn(getIOService(), true);
	tcp_conn.setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn.connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(! error_code);
	error_code = tcp_conn.handshake_client();
	BOOST_REQUIRE(! error_code);

	checkSendAndReceiveMessages(tcp_conn);
}
#endif

BOOST_AUTO_TEST_CASE(checkHelloServiceResponseContent) {
	checkWebServerResponseContent("HelloService", "/hello",
								  boost::regex(".*Hello\\sWorld.*"));
}

BOOST_AUTO_TEST_CASE(checkCookieServiceResponseContent) {
	checkWebServerResponseContent("CookieService", "/cookie",
								  boost::regex(".*<html>.*Cookie\\sService.*</html>.*"));
}

BOOST_AUTO_TEST_CASE(checkEchoServiceResponseContent) {
	checkWebServerResponseContent("EchoService", "/echo",
								  boost::regex(".*\\[Request\\sEcho\\].*\\[POST\\sContent\\].*"));
}

BOOST_AUTO_TEST_CASE(checkLogServiceResponseContent) {
#if defined(PION_USE_LOG4CXX) || defined(PION_USE_LOG4CPLUS) || defined(PION_USE_LOG4CPP)
	// make sure that the log level is high enough so that the entry will be recorded
	pion::PionLogger log_ptr = PION_GET_LOGGER("pion.net");
	PION_LOG_SETLEVEL_INFO(log_ptr);
	// make sure that the log service includes an entry for loading itself
	checkWebServerResponseContent("LogService", "/log",
								  boost::regex(".*Loaded.*plug-in.*\\(/log\\):\\sLogService.*"));
	// bump the log level back down when we are done with the test
	PION_LOG_SETLEVEL_WARN(log_ptr);
#elif defined(PION_DISABLE_LOGGING)
	checkWebServerResponseContent("LogService", "/log",
								  boost::regex(".*Logging\\sis\\sdisabled.*"));
#else
	checkWebServerResponseContent("LogService", "/log",
								  boost::regex(".*Using\\sostream\\slogging.*"));
#endif
}

#ifndef PION_STATIC_LINKING
BOOST_AUTO_TEST_CASE(checkAllowNothingServiceResponseContent) {
	checkWebServerResponseContent("AllowNothingService", "/deny",
								  boost::regex(".*No, you can't.*"),
								  HTTPTypes::RESPONSE_CODE_METHOD_NOT_ALLOWED);
}
#endif // PION_STATIC_LINKING

BOOST_AUTO_TEST_CASE(checkFileServiceResponseContent) {
	// load multiple services and start the server
	m_server.loadServiceConfig(SERVICES_CONFIG_FILE);
	m_server.start();

	// open a connection
	tcp::endpoint http_endpoint(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	tcp::iostream http_stream(http_endpoint);

	// send request and check response (index page)
	const boost::regex index_page_regex(".*<html>.*Test\\sWebsite.*</html>.*");
	checkWebServerResponseContent(http_stream, "/" , index_page_regex);
	checkWebServerResponseContent(http_stream, "/index.html" , index_page_regex);

	// send request and check response (copy of docs index page generated by doxygen)
	const boost::regex doc_index_regex(".*<html>.*pion-.*Documentation.*</html>.*");
	checkWebServerResponseContent(http_stream, "/doc/index.html" , doc_index_regex);
}

BOOST_AUTO_TEST_CASE(checkPionUserPasswordSanity) {
	const std::string clear_pw("deadmeat");
	PionUser u("test-user");
	u.setPassword(clear_pw);
	BOOST_CHECK(u.matchPassword(clear_pw));

#ifdef PION_HAVE_SSL
	std::string encrypted_pw = u.getPassword();
	BOOST_CHECK_EQUAL(encrypted_pw.size(), static_cast<unsigned int>(SHA_DIGEST_LENGTH * 2));
	BOOST_CHECK(clear_pw != encrypted_pw);

	u.setPasswordHash(encrypted_pw);
	BOOST_CHECK_EQUAL(encrypted_pw, u.getPassword());	// should still be identical
	BOOST_CHECK(u.matchPassword(clear_pw));
#endif
}

BOOST_AUTO_TEST_CASE(checkBasicAuthServiceFailure) {
	m_server.loadService("/auth", "EchoService");
	PionUserManagerPtr userManager(new PionUserManager());
	HTTPAuthPtr auth_ptr(new HTTPBasicAuth(userManager));
	m_server.setAuthentication(auth_ptr);
	auth_ptr->addRestrict("/auth");
	auth_ptr->addUser("mike", "123456");
	m_server.start();

	// open a connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	HTTPRequestWriterPtr writer(HTTPRequestWriter::create(tcp_conn));
	writer->getRequest().setMethod("POST");
	writer->getRequest().setResource("/auth/something/somewhere");

	writer << "junk";
	writer->send();

	// receive the response from the server
	HTTPResponse http_response(writer->getRequest());
	http_response.receive(*tcp_conn, error_code);
	BOOST_CHECK(!error_code);

	// check that the response is RESPONSE_CODE_UNAUTHORIZED
	BOOST_CHECK(http_response.getStatusCode() == HTTPTypes::RESPONSE_CODE_UNAUTHORIZED);
	BOOST_CHECK(http_response.getContentLength() > 0);

	// check the post content of the request, by parsing it out of the post content of the response
	boost::regex post_content(".*\\[POST Content]\\s*junk.*");
	BOOST_CHECK(!boost::regex_match(http_response.getContent(), post_content));
}

BOOST_AUTO_TEST_CASE(checkBasicAuthServiceLogin) {
	m_server.loadService("/auth", "EchoService");
	PionUserManagerPtr userManager(new PionUserManager());
	HTTPAuthPtr auth_ptr(new HTTPBasicAuth(userManager));
	m_server.setAuthentication(auth_ptr);
	auth_ptr->addRestrict("/auth");
	auth_ptr->addUser("mike", "123456");
	m_server.start();

	// open a connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	HTTPRequestWriterPtr writer(HTTPRequestWriter::create(tcp_conn));
	writer->getRequest().setMethod("POST");
	writer->getRequest().setResource("/auth/something/somewhere");
	// add an authentication for "mike:123456"
	writer->getRequest().addHeader(HTTPTypes::HEADER_AUTHORIZATION, "Basic bWlrZToxMjM0NTY=");

	writer << "junk";
	writer->send();

	// receive the response from the server
	HTTPResponse http_response(writer->getRequest());
	http_response.receive(*tcp_conn, error_code);
	BOOST_CHECK(!error_code);

	// check that the response is OK
	BOOST_CHECK(http_response.getStatusCode() == 200);
	BOOST_CHECK(http_response.getContentLength() > 0);

	// check the post content of the request, by parsing it out of the post content of the response
	boost::regex post_content(".*\\[POST Content]\\s*junk.*");
	BOOST_CHECK(boost::regex_match(http_response.getContent(), post_content));
}

BOOST_AUTO_TEST_CASE(checkCookieAuthServiceFailure) {
	m_server.loadService("/auth", "EchoService");
	PionUserManagerPtr userManager(new PionUserManager());
	HTTPAuthPtr auth_ptr(new HTTPCookieAuth(userManager));
	m_server.setAuthentication(auth_ptr);
	auth_ptr->addRestrict("/auth");
	auth_ptr->addUser("mike", "123456");
	m_server.start();

	// open a connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	HTTPRequestWriterPtr writer(HTTPRequestWriter::create(tcp_conn));
	writer->getRequest().setMethod("POST");
	writer->getRequest().setResource("/auth/something/somewhere");

	writer << "junk";
	writer->send();

	// receive the response from the server
	HTTPResponse http_response(writer->getRequest());
	http_response.receive(*tcp_conn, error_code);
	BOOST_CHECK(!error_code);

	// check that the response is RESPONSE_CODE_UNAUTHORIZED
	BOOST_CHECK(http_response.getStatusCode() == HTTPTypes::RESPONSE_CODE_UNAUTHORIZED);
	BOOST_CHECK(http_response.getContentLength() > 0);

	// check the post content of the request, by parsing it out of the post content of the response
	boost::regex post_content(".*\\[POST Content]\\s*junk.*");
	BOOST_CHECK(!boost::regex_match(http_response.getContent(), post_content));
}

BOOST_AUTO_TEST_CASE(checkCookieAuthServiceLogin) {
	m_server.loadService("/auth", "EchoService");
	PionUserManagerPtr userManager(new PionUserManager());
	HTTPAuthPtr auth_ptr(new HTTPCookieAuth(userManager));
	m_server.setAuthentication(auth_ptr);
	auth_ptr->addRestrict("/auth");
	auth_ptr->addUser("mike", "123456");
	m_server.start();

	// open a login connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	HTTPRequestWriterPtr writer(HTTPRequestWriter::create(tcp_conn));
	writer->getRequest().setMethod("GET");
	// login as "mike:123456"
	writer->getRequest().setResource("/login?user=mike&pass=123456");

	//writer << "junk";
	writer->send();

	// receive the response from the server
	HTTPResponse http_response(writer->getRequest());
	http_response.receive(*tcp_conn, error_code);
	BOOST_CHECK(!error_code);

	// check that the response is OK
	BOOST_CHECK(http_response.getStatusCode() == 204);
	BOOST_CHECK(http_response.getContentLength() == 0);
	BOOST_CHECK(http_response.hasHeader(HTTPTypes::HEADER_SET_COOKIE));
	// get Cookies
	std::string cookie = http_response.getHeader(HTTPTypes::HEADER_SET_COOKIE);

	// now try to connect to protected area using login cookie

	HTTPRequestWriterPtr writer2(HTTPRequestWriter::create(tcp_conn));
	writer2->getRequest().setMethod("POST");
	writer2->getRequest().setResource("/auth/something/somewhere");
	// add an authentications for "mike:123456"
	writer2->getRequest().addHeader(HTTPTypes::HEADER_COOKIE,cookie);

	writer2 << "junk";
	writer2->send();

	// receive the response from the server
	HTTPResponse http_response2(writer2->getRequest());
	http_response2.receive(*tcp_conn, error_code);
	BOOST_CHECK(!error_code);

	// check that the response is OK
	BOOST_CHECK(http_response2.getStatusCode() == 200);
	BOOST_CHECK(http_response2.getContentLength() > 0);

	// check the post content of the request, by parsing it out of the post content of the response
	boost::regex post_content(".*\\[POST Content]\\s*junk.*");
	BOOST_CHECK(boost::regex_match(http_response2.getContent(), post_content));
}

BOOST_AUTO_TEST_SUITE_END()

#define BIG_BUF_SIZE (12 * 1024)

///
/// ContentResponseWithoutLengthTests_F:
/// this uses a "big content buffer" to make sure that reading the response
/// content works across multiple packets (and asio_read_some() calls)
/// and when no content-length is specified (it should read through the end)
///
class ContentResponseWithoutLengthTests_F
	: public WebServerTests_F
{
public:
	// default constructor and destructor
	ContentResponseWithoutLengthTests_F() {
		// fill the buffer with non-random characters
		for (unsigned long n = 0; n < BIG_BUF_SIZE; ++n) {
			m_big_buf[n] = char(n);
		}
	}
	virtual ~ContentResponseWithoutLengthTests_F() {}

	/**
	 * sends an HTTP response with content, but not content-length provided
	 *
	 * @param request the HTTP request to respond to
	 * @param tcp_conn the TCP connection to send the response over
	 */
	void sendResponseWithContentButNoLength(HTTPRequestPtr& request,
											TCPConnectionPtr& tcp_conn)
	{
		// make sure it will get closed when finished
		tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_CLOSE);

		// prepare the response headers
		HTTPResponse http_response(*request);
		http_response.setDoNotSendContentLength();

		// send the response headers
		boost::system::error_code error_code;
		http_response.send(*tcp_conn, error_code);
		BOOST_REQUIRE(! error_code);

		// send the content buffer
		tcp_conn->write(boost::asio::buffer(m_big_buf, BIG_BUF_SIZE), error_code);
		BOOST_REQUIRE(! error_code);

		// finish (and close) the connection
		tcp_conn->finish();
	}

	/// reads in a HTTP response asynchronously
	void readAsyncResponse(TCPConnectionPtr& tcp_conn)
	{
		HTTPRequest http_request("GET");
		HTTPResponseReaderPtr reader_ptr(HTTPResponseReader::create(tcp_conn, http_request,
																	boost::bind(&ContentResponseWithoutLengthTests_F::checkResponse,
																	this, _1, _2, _3)));
		reader_ptr->receive();
	}

	/// checks the validity of the HTTP response
	void checkResponse(const HTTPResponse& http_response)
	{
		BOOST_REQUIRE(http_response.getStatusCode() == 200);
		BOOST_CHECK(! http_response.hasHeader(HTTPTypes::HEADER_CONTENT_LENGTH));
		BOOST_REQUIRE(http_response.getContentLength() == BIG_BUF_SIZE);
		BOOST_CHECK_EQUAL(memcmp(http_response.getContent(), m_big_buf, BIG_BUF_SIZE), 0);
	}

	/// checks the validity of the HTTP response
	void checkResponse(HTTPResponsePtr& response_ptr,
		TCPConnectionPtr& conn_ptr, const boost::system::error_code& ec)
	{
		checkResponse(*response_ptr);
		boost::mutex::scoped_lock async_lock(m_mutex);
		m_async_test_finished.notify_one();
	}

	/// big data buffer used for the tests
	char				m_big_buf[BIG_BUF_SIZE];

	/// signaled after the async response check has finished
	boost::condition	m_async_test_finished;

	/// used to protect the asynchronous operations
	boost::mutex		m_mutex;
};

// ContentResponseWithoutLengthTests_F Test Cases

BOOST_FIXTURE_TEST_SUITE(ContentResponseWithoutLengthTests_S, ContentResponseWithoutLengthTests_F)

BOOST_AUTO_TEST_CASE(checkSendContentWithoutLengthAndReceiveSyncResponse) {
	// startup the server
	m_server.addResource("/big", boost::bind(&ContentResponseWithoutLengthTests_F::sendResponseWithContentButNoLength,
											 this, _1, _2));
	m_server.start();

	// open a connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	// send an HTTP request
	HTTPRequest http_request("/big");
	http_request.send(*tcp_conn, error_code);
	BOOST_REQUIRE(! error_code);

	// receive the response from the server
	HTTPResponse http_response(http_request);
	http_response.receive(*tcp_conn, error_code);
	BOOST_REQUIRE(! error_code);

	// check that the response is OK
	checkResponse(http_response);
}

BOOST_AUTO_TEST_CASE(checkSendContentWithoutLengthAndReceiveAsyncResponse) {
	// startup the server
	m_server.addResource("/big", boost::bind(&ContentResponseWithoutLengthTests_F::sendResponseWithContentButNoLength,
											 this, _1, _2));
	m_server.start();

	// open a connection
	TCPConnectionPtr tcp_conn(new TCPConnection(getIOService()));
	boost::system::error_code error_code;
	error_code = tcp_conn->connect(boost::asio::ip::address::from_string("127.0.0.1"), m_server.getPort());
	BOOST_REQUIRE(!error_code);

	// send an HTTP request
	boost::mutex::scoped_lock async_lock(m_mutex);
	HTTPRequestWriterPtr request_ptr(HTTPRequestWriter::create(tcp_conn,
									 boost::bind(&ContentResponseWithoutLengthTests_F::readAsyncResponse,
												 this, tcp_conn)));
	request_ptr->getRequest().setResource("/big");
	request_ptr->send();

	// wait until the test is finished (and async calls have finished)
	m_async_test_finished.wait(async_lock);
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: naudhr/old-pion-net

max_issues_repo_name: naudhr/old-pion-net

max_forks_repo_name: naudhr/old-pion-net


text:
// Copyright (c) 2010, Adam Petersen <adam@adampetersen.se>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//   1. Redistributions of source code must retain the above copyright notice, this list of
//      conditions and the following disclaimer.
//
//   2. Redistributions in binary form must reproduce the above copyright notice, this list
//      of conditions and the following disclaimer in the documentation and/or other materials
//      provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY Adam Petersen ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Adam Petersen OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "tinch_pp/node.h"
#include "tinch_pp/mailbox.h"
#include "tinch_pp/erlang_types.h"
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <utility>

using namespace tinch_pp;
using namespace tinch_pp::erl;

// USAGE:
// ======
//
//  1. Start an Erlang node with a cookie set and a full node name.
//  2. Start net_kernel_sim with the same cookie.
//  3. Ping net_kernel_sim node.
//
// Example:
// ========
//  (testnode@127.0.0.1)1> net_adm:ping('net_adm_test_node@127.0.0.1').
//
//  Stop the program with:
//   (testnode@127.0.0.1)2> erlang:send({net_kernel,'net_adm_test_node@127.0.0.1'}, stop).

namespace {

void run_emulation(const std::string& node_name, const std::string& cookie);

void net_adm_emulator(mailbox_ptr mbox);

}

int main(int ac, char* av[])
{
  std::string node_name = "net_adm_test_node@127.0.0.1";
  const std::string cookie = "abcdef";

  run_emulation(node_name, cookie);
}

namespace {

void run_emulation(const std::string& node_name, const std::string& cookie)
{
  node_ptr my_node = node::create(node_name, cookie);

  my_node->publish_port(0xACDC);

  mailbox_ptr net_adm_mailbox = my_node->create_mailbox("net_kernel");
  boost::thread net_adm(boost::bind(&net_adm_emulator, net_adm_mailbox));

  net_adm.join();
}

void net_adm_emulator(mailbox_ptr mbox)
{
  bool is_running = true;

  while(is_running) {
    const matchable_ptr rec_msg = mbox->receive();

    // {atom, {pid, new_ref}, {atom, atom}}
    //
    // Sample msg = {$gen_call, {pid, ref}, { is_auth, anode@zarathustra }}
    std::string node;
    new_reference_type monitor_ref;
    tinch_pp::e_pid sender;

    if(rec_msg->match(make_e_tuple(atom("$gen_call"),
							                            make_e_tuple(pid(&sender), ref(&monitor_ref)),
							                            make_e_tuple(atom("is_auth"), atom(&node))))) {
      std::cout << "net_adm: Received ping from " << node << std::endl;
      // Reply: {Mref, Reply} where Reply = yes
      mbox->send(sender, make_e_tuple(ref(monitor_ref), atom("yes")));
    } else if(rec_msg->match(atom("stop"))) {
      std::cout << "net_adm: terminating upon request." << std::endl;
      is_running = false;
    } else {
      std::cout << "...but failed to match!" << std::endl;
    }
  }
}

}

ext: cpp


text:
/********************************************************************************
 *
 * This file is part of the Geneva library collection. The following license
 * applies to this file:
 *
 * ------------------------------------------------------------------------------
 * 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.
 * ------------------------------------------------------------------------------
 *
 * Note that other files in the Geneva library collection may use a different
 * license. Please see the licensing information in each file.
 *
 ********************************************************************************
 *
 * Geneva was started by Dr. Rüdiger Berlich and was later maintained together
 * with Dr. Ariel Garcia under the auspices of Gemfony scientific. For further
 * information on Gemfony scientific, see http://www.gemfomy.eu .
 *
 * The majority of files in Geneva was released under the Apache license v2.0
 * in February 2020.
 *
 * See the NOTICE file in the top-level directory of the Geneva library
 * collection for a list of contributors and copyright information.
 *
 ********************************************************************************/

#pragma once

// Global checks, defines and includes needed for all of Geneva
#include "common/GGlobalDefines.hpp"

// Standard headers go here
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
#include <array>

// Boost headers go here
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/rfc6455.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/lexical_cast.hpp>

// Geneva headers go here
#include "courtier/GCourtierEnums.hpp"
#include "courtier/GProcessingContainerT.hpp"

namespace Gem {
namespace Courtier {

/******************************************************************************************/
////////////////////////////////////////////////////////////////////////////////////////////
/******************************************************************************************/
/**
 * This class encapsulate a processable item that may be transmitted to a remote site,
 * equiped with a command.
 *
 * @tparam processable_type The type of the processable type
 * @tparam command_type The command set to be executed on the processable type
 */
template<
	typename processable_type
	, typename command_type
>
class GCommandContainerT {
	 ///////////////////////////////////////////////////////////////
	 friend class boost::serialization::access;

	 template<class Archive>
	 void serialize(Archive & ar, const unsigned int version) {
		 ar
		 & BOOST_SERIALIZATION_NVP(m_command)
		 & BOOST_SERIALIZATION_NVP(m_payload_ptr);
	 }
	 ///////////////////////////////////////////////////////////////

	 // Make sure processable_type adheres to the GProcessingContainerT interface
	 static_assert(
		 std::is_base_of<Gem::Courtier::GProcessingContainerT<processable_type, typename processable_type::result_type>, processable_type>::value
		 , "processable_type does not adhere to the GProcessingContainerT interface"
	 );

public:
	 //-------------------------------------------------------------------------
	 /**
	  * Initialization with a command only, in cases where no payload
	  * needs to be transported
	  *
	  * @param command The command to be executed
	  */
	 explicit GCommandContainerT(command_type command)
		 : m_command(command)
	 { /* nothing */ }

	 //-------------------------------------------------------------------------
	 /**
	  * Initialization with command and payload (in cases where a payload needs
	  * to be transferred)
	  *
	  * @param command The command to be executed
	  * @param payload_ptr The payload transported by this object
	  */
	 GCommandContainerT(
		 command_type command
		 , std::shared_ptr<processable_type> payload_ptr
	 )
		 : m_command(command)
		 , m_payload_ptr(payload_ptr)
	 { /* nothing */ }

	 //-------------------------------------------------------------------------
	 // Defaulted constructors, destructor and move assigment operator

	 GCommandContainerT() = default;
	 GCommandContainerT(GCommandContainerT<processable_type, command_type>&& cp) noexcept = default;
	 ~GCommandContainerT() = default;

	 GCommandContainerT<processable_type, command_type>& operator=(GCommandContainerT<processable_type, command_type>&& cp) noexcept = default;

	 //-------------------------------------------------------------------------
	 // Deleted copy-constructors and assignment operator -- the class is non-copyable

	 GCommandContainerT<processable_type, command_type>(const GCommandContainerT<processable_type, command_type>&) = delete;
	 GCommandContainerT<processable_type, command_type>& operator=(const GCommandContainerT<processable_type, command_type>&) = delete;

	 //-------------------------------------------------------------------------
	 /**
	  * Reset to a new command and payload or clear the object
	  *
	  * @return A reference to this object, so we can serialize it in one go
	  */
	 const GCommandContainerT<processable_type, command_type>& reset(
		 command_type command = command_type(0)
		 , std::shared_ptr<processable_type> payload_ptr = std::shared_ptr<processable_type>()
	 ) {
		 m_command = command;
		 m_payload_ptr = payload_ptr;
		 return *this;
	 }

	 //-------------------------------------------------------------------------
	 /**
	  * Setting of the command to be executed on the payload (possibly on the remote side)
	  * @param command The command to be executed on the payload
	  */
	 void set_command(command_type command) {
		 m_command = command;
	 }

	 //-------------------------------------------------------------------------
	 /**
	  * Retrieval of the command to be executed on the payload
	  * @return The command to be executed on the payload
	  */
	 command_type get_command() const noexcept {
		 return m_command;
	 }

	 //-------------------------------------------------------------------------
	 /**
	  * Retrieves the payload
	  */
	 std::shared_ptr<processable_type> get_payload() const {
		 return m_payload_ptr;
	 }

	 //-------------------------------------------------------------------------
	 /**
	  * Processing of the payload (if any)
	  *
	  * // TODO: Check for errors during processing
	  */
	 void process() {
		 if(m_payload_ptr) {
			 m_payload_ptr->process();
		 } else {
			 throw gemfony_exception(
				 g_error_streamer(DO_LOG,  time_and_place)
					 << "In GCommandContainerT<processable_type, command_type>::process():" << std::endl
					 << "Tried to process a work item while m_payload_ptr is empty" << std::endl
			 );
		 }
	 }

private:
	 //-------------------------------------------------------------------------
	 // Data

	 command_type m_command{command_type(0)}; ///< The command to be exeecuted
	 std::shared_ptr<processable_type>  m_payload_ptr; ///< The actual payload, if any

	 //-------------------------------------------------------------------------
};

/******************************************************************************/
////////////////////////////////////////////////////////////////////////////////
/******************************************************************************/
/**
 * Conversion of a GCommandContainerT to a string
 */
template<
	typename processable_type
	, typename command_type
>
std::string container_to_string(
	const GCommandContainerT<processable_type, command_type>& container
	, Gem::Common::serializationMode serMode
) {
	try {
		switch (serMode) {
			case Gem::Common::serializationMode::TEXT: {
				std::ostringstream oss;
				boost::archive::text_oarchive oa(oss);
				oa << boost::serialization::make_nvp(
					"command_container"
					, container
				);
				return oss.str();
			} break; // archive and stream closed at end of scope

			case Gem::Common::serializationMode::XML: {
				std::ostringstream oss;
				boost::archive::xml_oarchive oa(oss);
				oa << boost::serialization::make_nvp(
					"command_container"
					, container
				);
				return oss.str();
			} break;

			case Gem::Common::serializationMode::BINARY: {
				std::ostringstream oss(std::ios_base::binary);
				boost::archive::binary_oarchive oa(oss);
				oa << boost::serialization::make_nvp(
					"command_container"
					, container
				);
				return oss.str();
			} break;
		}
	} catch (const boost::system::system_error &e) {
		throw gemfony_exception(
			g_error_streamer(DO_LOG,  time_and_place)
				<< "In container_to_string(GCommandContainerT<>):" << std::endl
				<< "Caught boost::system::system_error exception with messages:" << std::endl
				<< e.what() << std::endl
				<< "with serializationMode == " << Gem::Common::serModeToString(serMode) << std::endl
		);
	} catch (const boost::exception &e) {
		throw gemfony_exception(
			g_error_streamer(DO_LOG,  time_and_place)
				<< "In container_to_string(GCommandContainerT<>):" << std::endl
				<< "Caught boost::exception exception with messages:" << std::endl
				<< boost::diagnostic_information(e) << std::endl
				<< "with serializationMode == " << Gem::Common::serModeToString(serMode) << std::endl
		);
	} catch (const std::exception& e) {
		throw gemfony_exception(
			g_error_streamer(
				DO_LOG
				, time_and_place
			)
				<< "In container_to_string(GCommandContainerT<>):" << std::endl
				<< "Caught std::exception exception with messages:" << std::endl
				<< e.what() << std::endl
				<< "with serializationMode == " << Gem::Common::serModeToString(serMode) << std::endl
		);
	} catch (...) {
		throw gemfony_exception(
			g_error_streamer(DO_LOG,  time_and_place)
				<< "In container_to_string(GCommandContainerT<>):" << std::endl
				<< "Caught unknown exception" << std::endl
				<< "with serializationMode == " << Gem::Common::serModeToString(serMode) << std::endl
		);
	}

	// Make the compiler happy
	return std::string();
}

/******************************************************************************/
/**
 * Loading of a GCommandContainerT from a string
 */
template<
	typename processable_type
	, typename command_type
>
void container_from_string(
	const std::string& descr
	, GCommandContainerT<processable_type, command_type>& container
	, Gem::Common::serializationMode serMode
) {
	container.reset();

	try {
		switch(serMode) {
			case Gem::Common::serializationMode::TEXT: {
				std::istringstream iss(descr);
				boost::archive::text_iarchive ia(iss);
				ia >> boost::serialization::make_nvp("command_container", container);
			} break; // archive and stream closed at end of scope

			case Gem::Common::serializationMode::XML: {
				std::istringstream iss(descr);
				boost::archive::xml_iarchive ia(iss);
				ia >> boost::serialization::make_nvp("command_container", container);
			} break;

			case Gem::Common::serializationMode::BINARY: {
				std::istringstream iss(descr, std::ios_base::binary);
				boost::archive::binary_iarchive ia(iss);
				ia >> boost::serialization::make_nvp("command_container", container);
			} break;
		}
	} catch (const boost::system::system_error &e) {
		throw gemfony_exception(
			g_error_streamer(
				DO_LOG
				,  time_and_place
			)
				<< "In container_from_string(GCommandContainerT<>):" << std::endl
				<< "Caught boost::system::system_error exception with messages:" << std::endl
				<< e.what() << std::endl
				<< "with serializationMode == " << Gem::Common::serModeToString(serMode) << std::endl
		);
	} catch (const boost::exception &e) {
		throw gemfony_exception(
			g_error_streamer(
				DO_LOG
				, time_and_place
			)
				<< "In container_from_string(GCommandContainerT<>):" << std::endl
				<< "Caught boost::exception exception with messages:" << std::endl
				<< boost::diagnostic_information(e) << std::endl
				<< "with serializationMode == " << Gem::Common::serModeToString(serMode) << std::endl
		);
	} catch (const std::exception& e) {
		throw gemfony_exception(
			g_error_streamer(
				DO_LOG
				, time_and_place
			)
				<< "In container_from_string(GCommandContainerT<>):" << std::endl
				<< "Caught std::exception exception with messages:" << std::endl
				<< e.what() << std::endl
				<< "with serializationMode == " << Gem::Common::serModeToString(serMode) << std::endl
		);
	} catch (...) {
		throw gemfony_exception(
			g_error_streamer(DO_LOG,  time_and_place)
				<< "In container_from_string(GCommandContainerT<>):" << std::endl
				<< "Caught unknown exception" << std::endl
				<< "with serializationMode == " << Gem::Common::serModeToString(serMode) << std::endl
		);
	}
};

/******************************************************************************/
////////////////////////////////////////////////////////////////////////////////
/******************************************************************************/

} /* namespace Courtier */
} /* namespace Gem */

/******************************************************************************/

ext: hpp

max_stars_repo_name: denisbertini/geneva

max_issues_repo_name: denisbertini/geneva

max_forks_repo_name: denisbertini/geneva


text:
/*    Copyright (c) 2010-2015, Delft University of Technology
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without modification, are
 *    permitted provided that the following conditions are met:
 *      - Redistributions of source code must retain the above copyright notice, this list of
 *        conditions and the following disclaimer.
 *      - Redistributions in binary form must reproduce the above copyright notice, this list of
 *        conditions and the following disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *      - Neither the name of the Delft University of Technology nor the names of its contributors
 *        may be used to endorse or promote products derived from this software without specific
 *        prior written permission.
 *
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 *    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *    AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *    OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      110519    F.M. Engelen      File created.
 *      110628    K. Kumar          Minor comment and layout modifications.
 *      110701    K. Kumar          Updated unit tests to check relative error;
 *                                  Updated file path.
 *      110718    F.M. Engelen      Took out falacy in test (only checking the norm) and
 *                                  added ItoE and EtoI transformation.
 *      110726    K. Kumar          Minor modifications; updated relative error
 *                                  wrt to norm.
 *      110808    F.M. Engelen      Updated with better tests, changed test for vertical frame.
 *      120529    E.A.G. Heeren     Boostified unit tests.
 *      120614    P. Musegaas       Removed unneccessary using statements and normalizations.
 *      130312    D. Dirkx          Added unit test for planet-fixed <-> inertial without equal
 *                                  equatorial frame.
 *      130312    A. Ronse          Added tests for V-T, TA-AA and AA-B transformations.
 *
 *    References
 *      Mooij, E. The Motion of a Vehicle in a Planetary Atmosphere, TU Delft, 1997.
 *
 *    Notes
 *      The reference frame definitions/abbreviations can be found in the file
 *      referenceFrameTransformations.h.
 *
 */

#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>

#include <Eigen/Core>

#include "Tudat/Basics/testMacros.h"
#include "Tudat/Astrodynamics/BasicAstrodynamics/unitConversions.h"

#include "Tudat/Astrodynamics/ReferenceFrames/referenceFrameTransformations.h"

namespace tudat
{
namespace unit_tests
{

using namespace unit_conversions;

BOOST_AUTO_TEST_SUITE( test_reference_frame_transformations )

// Summary of tests.
// Test 1: Test inertial to rotating planetocentric frame transformation.
// Test 2: Check whether the transformed matrix of Test 1 is also correct.
// Test 3: Same test as Test 1 for the transformation quaternion.
// Test 4: Same test as Test 2 for the transformation quaternion.
// Test 5: Test airspeed-based aerodynamic to body frame transformation.
// Test 6: Test planetocentric to local vertical frame transformation quaternion.
// Test 7: Check whether the transformed matrix of Test 6 is also correct.
// Test 8: Test transformations between trajectory and local vertical frame.
// Test 9: Test transformations between trajectory and aerodynamic frame.
// Test 10: Test transformations between body and aerodynamic reference frame.

// Test inertial to rotating planetocentric frame transformations.
BOOST_AUTO_TEST_CASE( testRotatingPlanetocentricFrameTransformations )
{
    // Using declarations.
    using std::atan2;
    using std::cos;
    using std::sin;
    using std::pow;
    using std::sqrt;

    // Test 1: Test Inertial to rotating planetocentric frame transformation.
    {
        // Initialize initial location vector in inertial frame.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = 4.0;
        startLocation( 1 ) = 1.0;
        startLocation( 2 ) = 5.0;

        double horizontalStartLocationSize = sqrt( pow( startLocation( 0 ), 2.0 )
                                                   + pow( startLocation( 1 ), 2.0 ) );

        // Declare and initialize angle between vector and XR-axis.
        double startAngle = atan2( startLocation( 1 ), startLocation( 0 ) );

        // Rotate by 10 degrees around the positive Z-axis
        double angleInTime = convertDegreesToRadians( 10.0 );

        // Declare and initialize the angle between the XI- and XR-axis.
        double endAngle = startAngle - angleInTime;

        // Declare the expected location of the point in the planetocentric reference frame.
        Eigen::Vector3d expectedLocation;
        expectedLocation( 0 ) = horizontalStartLocationSize * cos( endAngle );
        expectedLocation( 1 ) = horizontalStartLocationSize * sin( endAngle );
        expectedLocation( 2 ) = startLocation( 2 );

        // Compute location of the point in the rotating frame subject to the transformation
        // matrix.
        Eigen::Vector3d transformedLocation;
        transformedLocation = reference_frames::
                getInertialToPlanetocentricFrameTransformationMatrix( angleInTime )
                * startLocation;

        // Check whether both vectors are equal within tolerances.
        TUDAT_CHECK_MATRIX_CLOSE_FRACTION( transformedLocation, expectedLocation,
                                           std::numeric_limits< double >::epsilon( ) );
    }

    // Test 2: Check whether the transformed matrix of Test 1 is also correct.
    // Compute the error in the calculation.
    {
        // Initialize initial location vector in inertial frame.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = 4.0;
        startLocation( 1 ) = 1.0;
        startLocation( 2 ) = 5.0;

        // Rotate by 10 degrees around the positive Z-axis
        double angleInTime = convertDegreesToRadians( 10.0 );

        // Compute location of the point in the rotating frame subject to the transformation matrix.
        Eigen::Vector3d transformedLocation;
        transformedLocation = reference_frames::
                getRotatingPlanetocentricToInertialFrameTransformationMatrix( angleInTime ) *
                reference_frames::
                getInertialToPlanetocentricFrameTransformationMatrix( angleInTime )
                * startLocation;

        // Check whether both vectors are equal within tolerances.
        TUDAT_CHECK_MATRIX_CLOSE_FRACTION( transformedLocation, startLocation,
                                           std::numeric_limits< double >::epsilon( ) );
    }
}

BOOST_AUTO_TEST_CASE( testRotatingPlanetocentricFrameTransformationQuaternion )
{
    // Using declarations.
    using std::atan2;
    using std::cos;
    using std::sin;
    using std::pow;
    using std::sqrt;

    // Test 3: Same test as Test 1 for the transformation quaternion.
    // Compute location of the point in the Rotating frame subject to the transformation matrix.
    {
        // Initialize initial location vector in inertial frame.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = 4.0;
        startLocation( 1 ) = 1.0;
        startLocation( 2 ) = 5.0;

        double horizontalStartLocationSize = sqrt( pow( startLocation( 0 ), 2.0 )
                                                   + pow( startLocation( 1 ), 2.0 ) );

        // Declare and initialize angle between vector and XR-axis.
        double startAngle = atan2( startLocation( 1 ), startLocation( 0 ) );

        // Rotate by 10 degrees around the positive Z-axis
        double angleInTime = convertDegreesToRadians( 10.0 );

        // Declare and initialize the angle between the XI- and XR-axis.
        double endAngle = startAngle - angleInTime;

        // Declare the expected location of the point in the planetocentric reference frame.
        Eigen::Vector3d expectedLocation;
        expectedLocation( 0 ) = horizontalStartLocationSize * cos( endAngle );
        expectedLocation( 1 ) = horizontalStartLocationSize * sin( endAngle );
        expectedLocation( 2 ) = startLocation( 2 );

        // Compute location of the point in the rotating frame subject to the transformation matrix.
        Eigen::Vector3d transformedLocation;
        transformedLocation = reference_frames::
                getInertialToPlanetocentricFrameTransformationQuaternion( angleInTime )
                * startLocation;

        // Check whether both vectors are equal within tolerances.
        TUDAT_CHECK_MATRIX_CLOSE_FRACTION( transformedLocation, expectedLocation,
                                           std::numeric_limits< double >::epsilon( ) );
    }

// Test 4: Same test as Test 2 for the transformation quaternion.
// Compute the error in the calculation.
    {
        // Initialize initial location vector in inertial frame.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = 4.0;
        startLocation( 1 ) = 1.0;
        startLocation( 2 ) = 5.0;

        // Rotate by 10 degrees around the positive Z-axis
        double angleInTime = convertDegreesToRadians( 10.0 );

        // Compute location of the point in the rotating frame subject to the transformation matrix.
        Eigen::Vector3d transformedLocation;
        transformedLocation = reference_frames::
                getRotatingPlanetocentricToInertialFrameTransformationQuaternion( angleInTime ) *
                reference_frames::
                getInertialToPlanetocentricFrameTransformationQuaternion( angleInTime )
                * startLocation;

        // Check whether both vectors are equal within tolerances.
        TUDAT_CHECK_MATRIX_CLOSE_FRACTION( transformedLocation, startLocation,
                                           std::numeric_limits< double >::epsilon( ) );
    }
}

BOOST_AUTO_TEST_CASE( testAirspeedBasedAerodynamicToBodyFrameTransformation )
{
    // Using declarations.
    using std::atan2;
    using std::cos;

    // Test 5: Test airspeed-Based Aerodynamic to body frame transformation.
    // Declare and initialize the start location and angles.
    {
        // Initialize initial location vector in inertial frame.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = -10.0;
        startLocation( 1 ) = 0.0;
        startLocation( 2 ) = 0.0;

        double angleOfAttack = convertDegreesToRadians( 45.0 );
        double angleOfSideslip = convertDegreesToRadians( 60.0 );;

        // Compute expected location.
        // As there is only an angle of attack, the following simplified equations can be used.
        Eigen::Vector3d expectedLocation;
        expectedLocation( 0 ) = startLocation( 0 ) * cos( angleOfSideslip ) * cos( angleOfAttack );
        expectedLocation( 1 ) = startLocation( 0 ) * sin( angleOfSideslip );
        expectedLocation( 2 ) = startLocation( 0 ) * cos( angleOfSideslip ) * sin( angleOfAttack );

        // Compute location of the point in the rotating frame subject to the transformation matrix.
        Eigen::Vector3d transformedLocation;
        transformedLocation = reference_frames::
                getAirspeedBasedAerodynamicToBodyFrameTransformationMatrix(
                        angleOfAttack, angleOfSideslip ) * startLocation;

        // Check whether both vectors are equal within tolerances.
        TUDAT_CHECK_MATRIX_CLOSE_FRACTION( transformedLocation, expectedLocation, 1.0e-14 );
    }
}

BOOST_AUTO_TEST_CASE( testRotatingPlanetocentricToLocalVerticalFrameTransformationQuaternion )
{
    // Using declarations.
    using std::atan2;
    using std::cos;
    using std::sin;

    // Test 6: Test Rotating planetocentric to local vertical frame transformation quaternion.
    {
        // Initialize initial location vector.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = 10.0;
        startLocation( 1 ) = 5.0;
        startLocation( 2 ) = 2.0;

        // Declare rotation angle for planet and set to 90 degrees.
        double longitude = convertDegreesToRadians( 60.0 );

        // Declare latitude and set to 45 degrees.
        double latitude = convertDegreesToRadians( 20.0 );

        // Declare the expected location of the point in the planet reference frame.
        Eigen::Vector3d expectedLocation;
        expectedLocation( 0 ) = -cos( longitude ) * sin( latitude ) * startLocation( 0 ) -
                sin( longitude ) * sin( latitude ) * startLocation( 1 )  +
                cos( latitude ) * startLocation( 2 );
        expectedLocation( 1 ) = -sin( longitude ) * startLocation( 0 ) +
                cos( longitude ) * startLocation( 1 ) +
                0.0;
        expectedLocation( 2 ) = -cos( longitude ) * cos( latitude ) * startLocation( 0 ) -
                sin( longitude ) * cos( latitude ) * startLocation( 1 )  -
                sin( latitude ) * startLocation( 2 );

        // Compute location of the point in the rotating frame subject to the transformation matrix.
        Eigen::Vector3d transformedLocation;
        transformedLocation = reference_frames::
                getRotatingPlanetocentricToLocalVerticalFrameTransformationQuaternion(
                        longitude, latitude ) * startLocation;

        // Check whether both vectors are equal within tolerances.
        TUDAT_CHECK_MATRIX_CLOSE_FRACTION( transformedLocation, expectedLocation, 1.0e-14 );
    }

    // Test 7: Check whether the transformed matrix of Test 6 is also correct.
    // Compute the error in the calculation.
    {
        // Initialize initial location vector.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = 10.0;
        startLocation( 1 ) = 5.0;
        startLocation( 2 ) = 2.0;

        // Declare rotation angle for planet and set to 90 degrees.
        double longitude = convertDegreesToRadians( 60.0 );

        // Declare latitude and set to 45 degrees.
        double latitude = convertDegreesToRadians( 20.0 );

        // Compute location of the point in the rotating frame subject to the transformation matrix.
        Eigen::Vector3d transformedLocation;
        transformedLocation = reference_frames::
                getLocalVerticalToRotatingPlanetocentricFrameTransformationQuaternion( longitude,
                                                                                latitude )
                * reference_frames::
                getRotatingPlanetocentricToLocalVerticalFrameTransformationQuaternion( longitude,
                                                                                latitude )
                * startLocation;

        // Check whether both vectors are equal within tolerances.
        TUDAT_CHECK_MATRIX_CLOSE_FRACTION( transformedLocation, startLocation, 1.0e-14 );
    }
}

// Test inertial to rotating planetocentric frame transformations, without assumption of equal x-y
// planes.
BOOST_AUTO_TEST_CASE( testRotatingPlanetocentricWithEquatorChangeFrameTransformations )
{
    using namespace reference_frames;

    // Data from pck00010.tpc Spice kernel.
    const double venusPoleRightAscension = convertDegreesToRadians( 272.76 );
    const double venusPoleDeclination = convertDegreesToRadians( 67.16 );
    const double venusPrimeMeridianAtJ2000 = convertDegreesToRadians( 160.20 );

    // Set rotation, as calculated with Spice
    // (see Astrodynamics/Ephemerides/unitTestSimpleRotationalEphemeris.cpp).
    Eigen::Matrix3d spiceInitialRotationToTargetFrameMatrix;
    spiceInitialRotationToTargetFrameMatrix
            << -0.9548214974296336, 0.2665104385944917, 0.1314841974018291,
            -0.296591573568662, -0.882413772579987, -0.3652114078848295,
            0.01869081416890202, -0.3877088083617989, 0.9215923900425705;

    // Calculate given rotation to Venus-fixed frame.
    Eigen::Matrix3d calculatedTransformationMatrix = Eigen::Matrix3d(
                getInertialToPlanetocentricFrameTransformationQuaternion(
                    venusPoleDeclination, venusPoleRightAscension, venusPrimeMeridianAtJ2000 ) );

    // Compare calculated with Spice result.
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                spiceInitialRotationToTargetFrameMatrix, calculatedTransformationMatrix, 1.0E-15 );

    // Calculate inverse rotation.
    calculatedTransformationMatrix = Eigen::Matrix3d(
                getRotatingPlanetocentricToInertialFrameTransformationQuaternion(
                    venusPoleDeclination, venusPoleRightAscension,
                    venusPrimeMeridianAtJ2000 ) );

    // Multiply inverse rotation with Spice rotation to Venus-fixed frame. The two should be
    // orthonormal, so result should be the identity matrix.
    Eigen::Matrix3d matrixToCheck =
            spiceInitialRotationToTargetFrameMatrix * calculatedTransformationMatrix;

    // Check whether result is indeed (close to) identity matrix.
    for ( unsigned int i = 0; i < 3; i++ )
    {
        for ( unsigned int j = 0; j < 3; j++ )
        {
            if ( i == j )
            {
                BOOST_CHECK_CLOSE_FRACTION( matrixToCheck( i, j ), 1.0, 1.0E-15 );
            }
            else
            {
                BOOST_CHECK_SMALL( matrixToCheck( i, j ), 1.0E-15 );
            }
        }
    }
}

BOOST_AUTO_TEST_CASE( testTrajectoryToLocalVerticalFrameTransformations )
{
    // Using declarations.
    using std::cos;
    using std::sin;

    // Test 8: Test trajectory to local vertical frame and inverse transformations.
    {
        // Initialize initial location vector.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = 10.0;
        startLocation( 1 ) = 5.0;
        startLocation( 2 ) = 2.0;

        // Declare rotation angles.
        for ( double headingAngle = convertDegreesToRadians( 0.0 );
              headingAngle < convertDegreesToRadians( 360.0 );
              headingAngle += convertDegreesToRadians( 30.0 ) )
        {
            for ( double flightPathAngle = convertDegreesToRadians( -90.0 );
                  flightPathAngle < convertDegreesToRadians( 90.0 );
                  flightPathAngle += convertDegreesToRadians( 30.0 ) )
            {
                // Declare the expected location of the point in the V-frame (per Mooij 1997).
                Eigen::Vector3d expectedLocation;
                Eigen::Matrix3d rotation;
                rotation << cos( headingAngle ) * cos( flightPathAngle ),
                            -sin( headingAngle ),
                            cos( headingAngle ) * sin( flightPathAngle ),
                            sin( headingAngle ) * cos( flightPathAngle ),
                            cos( headingAngle ),
                            sin( headingAngle ) * sin( flightPathAngle ),
                            -sin( flightPathAngle ),
                            0.0,
                            cos( flightPathAngle );
                            expectedLocation = rotation * startLocation;

                // Compute location of the point in the V-frame using the tested function.
                Eigen::Vector3d transformedLocationQuat =
                        reference_frames::
                        getTrajectoryToLocalVerticalFrameTransformationQuaternion(
                                flightPathAngle, headingAngle ) * startLocation;
                Eigen::Vector3d transformedLocationMat =
                        reference_frames::getTrajectoryToLocalVerticalFrameTransformationMatrix(
                                flightPathAngle, headingAngle ) * startLocation;

                // Compute product of inverse rotations.
                Eigen::Vector3d inverseRotationProductMat =
                        reference_frames::getTrajectoryToLocalVerticalFrameTransformationMatrix(
                                flightPathAngle, headingAngle ) *
                        reference_frames::getLocalVerticalFrameToTrajectoryTransformationMatrix(
                                flightPathAngle, headingAngle ) * startLocation;
                Eigen::Vector3d inverseRotationProductQuat =
                        reference_frames::
                        getTrajectoryToLocalVerticalFrameTransformationQuaternion(
                                flightPathAngle, headingAngle ) *
                        reference_frames::
                        getLocalVerticalFrameToTrajectoryTransformationQuaternion(
                                flightPathAngle, headingAngle ) * startLocation;

                // Check whether transformed vectors match within tolerances.
                TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                        transformedLocationQuat, expectedLocation, 1.0e-14 );
                TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                        transformedLocationMat, expectedLocation, 2.0e-14 );

                // Check whether product of inverse rotations equals unity.
                TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                        inverseRotationProductMat, startLocation, 1.0e-14 );
                TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                        inverseRotationProductQuat, startLocation, 1.0e-14 );
            }
        }
    }
}

BOOST_AUTO_TEST_CASE( testTrajectoryToAerodynamicFrameTransformations )
{
    // Using declarations.
    using std::cos;
    using std::sin;

    // Test 9: Test trajectory to aerodynamic and inverse transformations.
    {
        // Initialize initial location vector.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = 10.0;
        startLocation( 1 ) = 5.0;
        startLocation( 2 ) = 2.0;

        // Declare rotation angles.
        for ( double bankAngle = convertDegreesToRadians( 0.0 );
              bankAngle < convertDegreesToRadians( 360.0 );
              bankAngle += convertDegreesToRadians( 30.0 ) )
        {
            // Declare the expected location of the point in the aerodynamic reference frame
            // (per Mooij 1997).
            Eigen::Vector3d expectedLocation;
            Eigen::Matrix3d rotation;
            rotation << 1.0, 0.0, 0.0,
                        0.0, cos( bankAngle ), -sin( bankAngle ),
                        0.0, sin( bankAngle ), cos( bankAngle );
            expectedLocation = rotation * startLocation;

            // Compute location of the point in the rotating frame subject to the
            // transformation matrix.
            Eigen::Vector3d transformedLocationQuat =
                    reference_frames::getTrajectoryToAerodynamicFrameTransformationQuaternion(
                            bankAngle ) * startLocation;
            Eigen::Vector3d transformedLocationMat =
                    reference_frames::getTrajectoryToAerodynamicFrameTransformationMatrix(
                            bankAngle ) * startLocation;

            // Compute product of inverse rotations.
            Eigen::Vector3d inverseRotationProductMat =
                    reference_frames::getAerodynamicToTrajectoryFrameTransformationMatrix(
                            bankAngle ) *
                    reference_frames::getTrajectoryToAerodynamicFrameTransformationMatrix(
                            bankAngle ) * startLocation;
            Eigen::Vector3d inverseRotationProductQuat =
                    reference_frames::getAerodynamicToTrajectoryFrameTransformationQuaternion(
                            bankAngle ) *
                    reference_frames::getTrajectoryToAerodynamicFrameTransformationQuaternion(
                            bankAngle ) * startLocation;

            // Check whether transformed vectors match within tolerances.
            TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                    transformedLocationQuat, expectedLocation, 1.0e-14 );
            TUDAT_CHECK_MATRIX_CLOSE_FRACTION( transformedLocationMat, expectedLocation, 1.0e-14 );

            // Check whether product of inverse rotations equals unity.
            TUDAT_CHECK_MATRIX_CLOSE_FRACTION( inverseRotationProductMat, startLocation, 1.0e-14 );
            TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                    inverseRotationProductQuat, startLocation, 1.0e-14 );
        }
    }
}

BOOST_AUTO_TEST_CASE( testAerodynamicToBodyFrameTransformations )
{
    // Using declarations.
    using std::cos;
    using std::sin;

    // Test 10: Test body to airspeed-based aerodynamic frame and inverse transformations.
    {
        // Initialize initial location vector.
        Eigen::Vector3d startLocation;
        startLocation( 0 ) = 10.0;
        startLocation( 1 ) = 5.0;
        startLocation( 2 ) = 2.0;

        // Declare rotation angles.
        for ( double angleOfAttack = convertDegreesToRadians( -180.0 );
              angleOfAttack < convertDegreesToRadians( 180.0 );
              angleOfAttack += convertDegreesToRadians( 30.0 ) )
        {
            for ( double angleOfSideslip = convertDegreesToRadians( -90.0 );
                  angleOfSideslip < convertDegreesToRadians( 90.0 );
                  angleOfSideslip += convertDegreesToRadians( 30.0 ) )
            {
                // Declare the expected location of the point in the AA-frame.
                // (per Mooij 1997).
                Eigen::Vector3d expectedLocation;
                Eigen::Matrix3d rotation;
                rotation << cos( angleOfAttack ) * cos( angleOfSideslip ),
                            sin( angleOfSideslip ),
                            sin( angleOfAttack ) * cos( angleOfSideslip ),
                            -cos( angleOfAttack ) * sin( angleOfSideslip ),
                            cos( angleOfSideslip ),
                            -sin( angleOfAttack ) * sin( angleOfSideslip ),
                            -sin( angleOfAttack ),
                            0.0,
                            cos( angleOfAttack );
                expectedLocation = rotation * startLocation;

                // Compute location of the point in the AA-frame using the tested function.
                Eigen::Vector3d transformedLocationQuat =
                        reference_frames::
                        getBodyToAirspeedBasedAerodynamicFrameTransformationQuaternion(
                                angleOfAttack, angleOfSideslip ) * startLocation;
                Eigen::Vector3d transformedLocationMat =
                        reference_frames::
                        getBodyToAirspeedBasedAerodynamicFrameTransformationMatrix(
                                angleOfAttack, angleOfSideslip ) * startLocation;

                // Compute product of inverse rotations
                Eigen::Vector3d inverseRotationProductMat =
                        reference_frames::
                        getAirspeedBasedAerodynamicToBodyFrameTransformationMatrix(
                                angleOfAttack, angleOfSideslip ) *
                        reference_frames::
                        getBodyToAirspeedBasedAerodynamicFrameTransformationMatrix(
                                angleOfAttack, angleOfSideslip ) * startLocation;
                Eigen::Vector3d inverseRotationProductQuat =
                        reference_frames::
                        getAirspeedBasedAerodynamicToBodyFrameTransformationQuaternion(
                                angleOfAttack, angleOfSideslip ) *
                        reference_frames::
                        getBodyToAirspeedBasedAerodynamicFrameTransformationQuaternion(
                                angleOfAttack, angleOfSideslip ) * startLocation;

                // Check whether transformed vectors match within tolerances.
                TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                        transformedLocationQuat, expectedLocation, 1.0e-14 );
                TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                        transformedLocationMat, expectedLocation, 1.0e-14 );

                // Check whether product of inverse rotations equals unity.
                TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                        inverseRotationProductMat, startLocation, 1.0e-14 );
                TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                        inverseRotationProductQuat, startLocation, 1.0e-14 );
            }
        }
    }
}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat

max_stars_repo_name: JPelamatti/ThesisTUDAT

max_issues_repo_name: JPelamatti/ThesisTUDAT

max_forks_repo_name: JPelamatti/ThesisTUDAT


text:
#include <lost.hpp>
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "LOST tests"
#include <boost/test/unit_test.hpp>

boost::adjacency_list<boost::hash_setS, boost::vecS, boost::undirectedS> typedef graph;

BOOST_AUTO_TEST_CASE( info_branch_test )
{
  // 0-1-2-3-4-5-6
  //     |   |
  //     7   9
  //     |   |
  //     8   10
  graph T;
  add_edge(0, 1, T);
  add_edge(1, 2, T);
  add_edge(2, 3, T);
  add_edge(3, 4, T);
  add_edge(4, 5, T);
  add_edge(5, 6, T);
  add_edge(2, 7, T);
  add_edge(7, 8, T);
  add_edge(4, 9, T);
  add_edge(9, 10, T);
  leaf_info<graph> info(T);
  BOOST_CHECK( !info.is_path() );
  for(int i = 0; i < 3; ++i)
    BOOST_CHECK( info.on_branch(0, i) );
  for(int i = 3; i < 11; ++i)
    BOOST_CHECK( !info.on_branch(0, i) );
}

max_stars_repo_name: arekolek/MaxIST

max_issues_repo_name: arekolek/MaxIST

max_forks_repo_name: arekolek/MaxIST


text:
#include <boost/python.hpp>

#include "python/module.hpp"

#include "python/graph.hpp"
#include "simulation.hpp"

  // // functions
  // // class_< uniform_mass<vec3>, std::shared_ptr< uniform_mass<vec3>>,
  // // 		  bases<metric_base> >("uniform_mass_vec3");

namespace python {

  // TODO move ?where ?!
  struct simulation : graph, module<simulation> {
	static void module() {
	  using namespace boost::python;
	  using ::simulation;

      static auto get_gravity = +[](simulation* self) {
        return numpy::ndarray(self->gravity.data(), {3});
      };

      static auto set_gravity = +[](simulation* self, object obj) {
        get_gravity(self)[boost::python::slice()] = obj;
      };

	  class_<simulation, std::shared_ptr<simulation> > ("simulation")
		.def("step", &simulation::step)
		.def("init", &simulation::init)
		.def("reset", &simulation::reset)
        .add_property("gravity", get_gravity, set_gravity)
		;

	}
  };

}

// // Declare the actual type
BOOST_PYTHON_MODULE(pouf) {
  python::init_module();
}

max_stars_repo_name: maxime-tournier/cpp

max_issues_repo_name: maxime-tournier/cpp

max_forks_repo_name: maxime-tournier/cpp


text: #include <boost/preprocessor/repetition/deduce_z.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
//
// receiver.cpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>

namespace io = boost::asio;
namespace ip = boost::asio::ip;
namespace sys = boost::system;

const short multicast_port = 3937;
const char* multicast_group = "239.0.2.129";

class receiver {

  public:
    receiver(io::io_service& io_service, const ip::address& listen_address,
             const ip::address& multicast_address, const short port)
        : socket_(io_service)
    {
        // Create the socket so that multiple may be bound to the same
        // address.
        ip::udp::endpoint listen_endpoint(listen_address, port);
        socket_.open(listen_endpoint.protocol());
        socket_.set_option(ip::udp::socket::reuse_address(true));
        socket_.bind(listen_endpoint);

        // Join the multicast group.
        socket_.set_option(ip::multicast::join_group(multicast_address));

        socket_.async_receive_from(
            io::buffer(data_, max_length), sender_endpoint_,
            boost::bind(&receiver::handle_receive_from, this,
                        io::placeholders::error,
                        io::placeholders::bytes_transferred));
    }

    void handle_receive_from(const sys::error_code& error, size_t bytes_recvd)
    {

        if (!error) {
            std::cout.write(data_, bytes_recvd);
            std::cout << std::endl;

            socket_.async_receive_from(
                io::buffer(data_, max_length), sender_endpoint_,
                boost::bind(&receiver::handle_receive_from, this,
                            io::placeholders::error,
                            io::placeholders::bytes_transferred));
        }
    }

  private:
    ip::udp::socket socket_;
    ip::udp::endpoint sender_endpoint_;
    enum { max_length = 1024 };
    char data_[max_length];
};

int main()
{
    try {
        io::io_service io_service;
        receiver r(io_service, ip::address::from_string("0.0.0.0"),
                   ip::address::from_string(multicast_group), multicast_port);
        io_service.run();
    }
    catch (std::exception& e) {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}

max_stars_repo_name: virgiliosanz/Tests

max_issues_repo_name: virgiliosanz/Tests

max_forks_repo_name: virgiliosanz/Tests


text:
//==================================================================================================
/*!
  @file

  Copyright 2015 NumScale SAS
  Copyright 2015 J.T.Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_SCALAR_IS_GT_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_SCALAR_IS_GT_HPP_INCLUDED

#include <boost/simd/function/definition/is_gt.hpp>
#include <boost/simd/arch/common/scalar/function/is_greater.hpp>

#endif


text:
/*
Author: Gudakov Ramil Sergeevich a.k.a. Gauss
Гудаков Рамиль Сергеевич
Contacts: [ramil2085@mail.ru, ramil2085@gmail.com]
See for more information LICENSE.md.
*/

#include "HandlerMMO_Client.h"
#include "MMOEngine/include/BaseEvent.h"
#include "MMOEngine/include/Events.h"
#include "MMOEngine/include/Client.h"
#include "MMOEngine/include/EnumMMO.h"
#include <boost/asio/ip/impl/address_v4.ipp>
#include "CommonParam.h"
#include "ResolverSelf_IP_v4.h"
#include "Logger.h"

THandlerMMO_Client::THandlerMMO_Client() : THandlerMMO( nullptr, eClient )
{
}
//-----------------------------------------------------------------------------------
void THandlerMMO_Client::HandleFromMMOEngine( nsEvent::TEvent* pEvent )
{
  nsMMOEngine::TBaseEvent* pBE = ( nsMMOEngine::TBaseEvent* )pEvent->pContainer->GetPtr();
  nsMMOEngine::TClient* pClient = ( nsMMOEngine::TClient* )pEvent->pSrc;

  std::string sEvent;
  switch ( pBE->mType )
  {
    case nsMMOEngine::eTryConnectDown:
      BL_FIX_BUG();
      break;
    case nsMMOEngine::eConnectUp:
      BL_FIX_BUG();
      //sEvent = "ConnectUp";
      //AddConnection( ((nsMMOEngine::TConnectUpEvent*) pBE)->sessionID );
      break;
    case nsMMOEngine::eDisconnectUp:
      sEvent = "DisconnectUp";
      AddConnectedClient( pClient );
      //RemoveConnection( 1 );// ( ( nsMMOEngine::TDisconnectUpEvent* ) pBE )->sessionID );
      break;
    case nsMMOEngine::eError:
    {
      nsMMOEngine::TErrorEvent* pEr = ( nsMMOEngine::TErrorEvent* )pBE;
      sEvent = nsMMOEngine::GetStrError( pEr->code );
      GetLogger( ClientLog )->WriteF( "MMOEngine: %s.\t\n", sEvent.data() );
    }
    break;
    case nsMMOEngine::eRecvFromUp:
    {
      sEvent = "RecvFromUp";
      nsMMOEngine::TRecvFromUpEvent* pR = ( nsMMOEngine::TRecvFromUpEvent* )pBE;
      int index = std::atoi( (const char*)pR->GetData() );
      auto desc = mArrClient[index];
      desc->RecvPong();

      mPingSumma += desc->mLastIntervalPingPongTime;
      mPingCounter++;
      mWorthPing = std::max( desc->mLastIntervalPingPongTime, mWorthPing );
      mBestPing = std::min( desc->mLastIntervalPingPongTime, mBestPing );
    }
    break;
    case nsMMOEngine::eResultLogin:
    {
      sEvent = "ResultLogin";
      auto pRes = ( nsMMOEngine::TResultLoginEvent* )pBE;
      if ( pRes->res == nsMMOEngine::TMaster::eAccept )
      {
        sEvent += " Accept ";

        mClientDescMap[pClient]->flgNeedSendPing = true;

        //AddConnection( 1 );
        RemoveConnectedClient( pClient );
      }
      else
        sEvent += " Reject ";
      sEvent.append( pRes->c.GetPtr(), pRes->c.GetSize() );
      GetLogger( ClientLog )->WriteF( "MMOEngine: %s\t\n", sEvent.data() );
    }
    break;
    case nsMMOEngine::eEnterInQueue:
    {
      sEvent = "InQueueLoginClient";
      auto pEnterEvent = ( nsMMOEngine::TEnterInQueueEvent* )pBE;
      //pClient->LeaveQueue();
      auto numInQueue = pEnterEvent->numInQueue;
      GetLogger( ClientLog )->WriteF( "MMOEngine: %s, num = %d.\t\n", sEvent.data(), numInQueue );
    }
    break;
    case nsMMOEngine::eLeaveQueue:
      sEvent = "LeaveQueue";
      break;
    default:BL_FIX_BUG();
  }

  if ( pBE->mType == nsMMOEngine::eError )
    GetLogger( ClientLog )->WriteF( "MMOEngine: %s.\t\n", sEvent.data() );
}
//---------------------------------------------------------------------------------------------
void THandlerMMO_Client::WorkInherit()
{
  for ( int i = 0; i < mArrClient.size(); i++ )
  {
    auto descClient = mArrClient[i];
    if ( descClient->flgNeedSendPing )
    {
      descClient->SendPing( i );
      continue;
    }
  }
}
//---------------------------------------------------------------------------------------------

max_stars_repo_name: RamilGauss/MMO-Framework

max_issues_repo_name: RamilGauss/MMO-Framework

max_forks_repo_name: RamilGauss/MMO-Framework


text:
#include "automaton/core/storage/persistent_blobstore.h"

#include <string>

#include <boost/filesystem.hpp>
#include <boost/iostreams/device/mapped_file.hpp>

namespace automaton {
namespace core {
namespace storage {

persistent_blobstore::persistent_blobstore()
    : next_free(1024/4)
    , capacity(1024)
    , header_size(1024)
    , cur_version(10000)
    , is_mapped(false) {
  // TODO(Samir): Remove from constructor and do it when creating blob
  // storage = new uint32_t[1ULL << 28];
  // capacity = 1ULL << 28;
}

persistent_blobstore::~persistent_blobstore() {
  mmf.close();
}

uint8_t* persistent_blobstore::create_blob(const uint32_t size, uint64_t* id) {
  if (is_mapped == false) {
    throw std::logic_error("not mapped");;
  }

  uint32_t size_in_int32 =  size % 4 ? size / 4 + 1 : size / 4;
  *id = next_free;
  // When the capacity is not large enough to store the required blob,
  // allocate a new memory block with double the size and copy the data.
  if (next_free + size_in_int32 >= capacity) {
    close_mapped_file();
    capacity *= 2;
    boost::filesystem::path boost_path(file_path);
    boost::filesystem::resize_file(boost_path, capacity*sizeof(int32_t));
    open_mapped_file();
  }
  // Save the size of the blob
  storage[next_free] = size;
  // set the pointer to point to the blob
  uint8_t* out_blob_pointer = reinterpret_cast<uint8_t*>(&storage[next_free+1]);
  // next free equal to byte after the end of the blob
  next_free += size_in_int32 + 1;

  return out_blob_pointer;
}

uint64_t persistent_blobstore::store(const uint32_t size, const uint8_t* data) {
  if (is_mapped == false) {
    throw std::logic_error("not mapped");;
  }

  uint64_t id = 0;
  uint8_t* blob = create_blob(size, &id);
  std::memcpy(blob, data, size);
  return id;
}

uint8_t* persistent_blobstore::get(const uint64_t id, uint32_t* size) {
  if (is_mapped == false) {
    throw std::logic_error("not mapped");;
  }

  // check if id is out of range
  if (id+1 >= capacity) {
    throw std::out_of_range("Object out of range");
  }
  *size = storage[id];
  if (*size <= 0) {
    return nullptr;
  }
  return reinterpret_cast<uint8_t*>(&storage[id + 1]);
}

bool persistent_blobstore::free(const uint32_t id) {
  if (is_mapped == false) {
    throw std::logic_error("not mapped");;
  }
  if (id+1 >= capacity) {
    throw std::out_of_range("Object out of range");
  }
  // TODO(Samir): Change storage to unt8_t. Mark deleted nodes with *= -1
  storage[id] *= -1;
  return 1;
}

bool persistent_blobstore::map_file(std::string path) {
  if (mmf.is_open() || is_mapped) {
    return false;
  }

  file_path = path;

  if (boost::filesystem::exists(path)) {
    mmf.open(path, boost::iostreams::mapped_file::mapmode::readwrite);
    storage = reinterpret_cast<uint32_t*>(mmf.data());
    capacity = mmf.size() / 4;
    memcpy(&header_version, storage, sizeof(uint64_t));
  } else {
    boost::iostreams::mapped_file_params new_mmf(path);
    new_mmf.flags = boost::iostreams::mapped_file::mapmode::readwrite;
    // The starting size is 2KB by default, we should add a option set the starting size
    new_mmf.new_file_size = 1ULL << 10;
    capacity = new_mmf.new_file_size / 4;
    mmf.open(new_mmf);
    // write the version to the header of the new file
    storage = reinterpret_cast<uint32_t*>(mmf.data());
    uint64_t* header = reinterpret_cast<uint64_t*>(storage);
    header_version = cur_version;
    *header = header_version;
  }
  is_mapped = true;
  return true;
}

void persistent_blobstore::close_mapped_file() {
  mmf.close();
  is_mapped = false;
}

void persistent_blobstore::open_mapped_file() {
  mmf.open(file_path, boost::iostreams::mapped_file::mapmode::readwrite);
  storage = reinterpret_cast<uint32_t*>(mmf.data());
  capacity = mmf.size() / 4;
  is_mapped = true;
}

}  //  namespace storage
}  //  namespace core
}  //  namespace automaton

ext: cc

max_stars_repo_name: sept-en/automaton

max_issues_repo_name: sept-en/automaton

max_forks_repo_name: sept-en/automaton