<commit_before>/**
   MiracleGrue - Model Generator for toolpathing. <http://www.grue.makerbot.com>
   Copyright (C) 2011 Far McKon <Far@makerbot.com>, Hugo Boyer (hugo@makerbot.com)

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

**/
#include "abstractable.h"

using namespace mgl;
using namespace std;

#include "log.h"

#ifdef __APPLE__
#include <CFBundle.h>
#endif

#ifdef WIN32
#include <Windows.h>
#include <Shlobj.h>
#else
#include <sys/types.h>
#include <pwd.h>
#endif

#include <fstream>

std::ostream &MyComputer::log()
{
    return cout;
}

#ifdef QT_CORE_LIB
int FileSystemAbstractor::guarenteeDirectoryExists(const char* )//pathname  )
{
    Log::info() << "not supported on QT" << endl;
    return -1;
#else
int FileSystemAbstractor::guarenteeDirectoryExists(const char* pathname)
{
    int status = 0;

#ifdef WIN32
        DWORD attrib = GetFileAttributes(pathname);

        if (attrib == INVALID_FILE_ATTRIBUTES) {
            BOOL result = CreateDirectoryA(pathname, NULL);
            if (!result)
                status = -1; //creation fail
        }
        else if (!(attrib & FILE_ATTRIBUTE_DIRECTORY))
            status = -1;

#else //WIN32
        // mode_t does not work under QT
        mode_t mode =  (S_IREAD|S_IWRITE |S_IRGRP|S_IWGRP |S_IROTH);

		struct stat st;
		if(stat(pathname,&st) != 0){
			mode_t process_mask = umask(0);
			int result_code = mkdir(pathname, mode);
			umask(process_mask);
			if(result_code != 0)
				status = -1 ; //creation fail
		}
		else if (!S_ISDIR(st.st_mode))
			status = -1;
		return status;
#endif //!WIN32
#endif //!QT_CORE_LIB

}

string FileSystemAbstractor::pathJoin(string path, string filename) const
{
#ifdef WIN32
    return path  + "\\" + filename;
#else
	return path  + "/" + filename;
#endif
}

char FileSystemAbstractor::getPathSeparatorCharacter() const
{
#ifdef WIN32
    return '\\';
#else
    return '/'; // Linux & Mac, works on Windows most times
#endif
}

string FileSystemAbstractor::ExtractDirectory(const char *directoryPath) const
{
	const string path(directoryPath);
	return path.substr(0, path.find_last_of(getPathSeparatorCharacter()) + 1);
}

string FileSystemAbstractor::ExtractFilename(const char* filename) const
{
	std::string path(filename);
	return path.substr(path.find_last_of(getPathSeparatorCharacter()) + 1);
}

string FileSystemAbstractor::ChangeExtension(const char* filename, const char* extension) const
{
	const string path(filename);
	const string ext(extension);
	std::string filenameStr = ExtractFilename(path.c_str());
	return ExtractDirectory(path.c_str())
			+ filenameStr.substr(0, filenameStr.find_last_of('.')) + ext;
}

string FileSystemAbstractor::removeExtension(const char *filename) const
{
	const string path(filename);
	string filenameStr = ExtractFilename(path.c_str());
	return ExtractDirectory(path.c_str())
			+ filenameStr.substr(0, filenameStr.find_last_of('.'));
}

bool FileSystemAbstractor::fileReadable(const char *filename) const {
	ifstream testfile(filename, ifstream::in);
	bool readable = !testfile.fail();
	testfile.close();

	return readable;
}

string FileSystemAbstractor::getDataFile(const char *filename) const {
	string found = getUserDataFile(filename);
	if (found.length() > 0 && fileReadable(found.c_str()))
		return found;

	found = getSystemDataFile(filename);
	if (found.length() > 0 && fileReadable(found.c_str()))
		return found;

	return string();
}

string FileSystemAbstractor::getConfigFile(const char *filename) const {
	string found = getUserConfigFile(filename);
	if (found.length() > 0 && fileReadable(found.c_str()))
		return found;

	found = getSystemConfigFile(filename);
	if (found.length() > 0 && fileReadable(found.c_str()))
		return found;

	return string();
}

string FileSystemAbstractor::getUserDataFile(const char *filename) const {
#ifdef __APPLE__
	char pwbuff[1024];
	struct passwd pw;
	struct passwd *tempptr;
	if (getpwuid_r(getuid(), &pw, pwbuff, 1024, &tempptr) == 0) {
	   return pathJoin(pathJoin(string(pw.pw_dir),
								 "Library/Makerbot/Miracle-Grue"),
					   filename);
	}
	else {
		return string();
	}
#else
	/*other platforms should be fine putting user data files in the same
	  dir as user config files*/
	return getUserConfigFile(filename);
#endif
}

string FileSystemAbstractor::getSystemDataFile(const char *filename) const {
#ifdef __linux__
	return pathJoin(string("/usr/share/makerbot"), filename);
#else
	return getSystemConfigFile(filename);
#endif
}

string FileSystemAbstractor::getSystemConfigFile(const char *filename) const {
#ifdef WIN32
    char app_path[1024];

	GetModuleFileNameA(0, app_path, sizeof(app_path) - 1);

	// Extract directory
	std::string app_dir = ExtractDirectory(app_path);
	return pathJoin(app_dir, filename);

#elif defined __APPLE__
	CFBundleRef mainBundle;

	mainBundle = CFBundleGetMainBundle();
	if(!mainBundle)
		return string();

	CFURLRef resourceURL;
	resourceURL =
		CFBundleCopyResourceURL(mainBundle,
					CFStringCreateWithCString(NULL,
											  filename,
											  kCFStringEncodingASCII),

								NULL,
								NULL);

	if (!resourceURL)
		return string();

	char fileurl[1024];
	if(!CFURLGetFileSystemRepresentation(resourceURL,
										 true,
										 (UInt8*)
										 fileurl,
										 1024)) {
		return string();
	}

	return string(fileurl);
#else //linux

	return pathJoin(string("/etc/xdg/makerbot"), filename);
#endif
}

string FileSystemAbstractor::getUserConfigFile(const char *filename) const {
#ifdef WIN32
	char app_data[1024];
	if(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0,
								 app_data))) {
		return pathJoin(pathJoin(string(app_data), "Makerbot"),
						filename);
	}
#else //linux or apple
	char pwbuff[1024];
	struct passwd pw;
	struct passwd *tempptr;
	if (getpwuid_r(getuid(), &pw, pwbuff, 1024, &tempptr) == 0) {

#ifdef __APPLE__
		return pathJoin(pathJoin(string(pw.pw_dir),
								 "Library/Preferences/Makerbot/Miracle-Grue"),
						filename);
#else //linux
		return pathJoin(pathJoin(string(pw.pw_dir), ".config/makerbot"),
						filename);
#endif //linux
	}

#endif //win32

	return string();
}

ProgressLog::ProgressLog(unsigned int count)
    :ProgressBar(count,"")
{
	reset(count);
	std::cout << ":";

}

void ProgressLog::onTick(const char* taskName, unsigned int count, unsigned int ticks)
{
	if (ticks == 0) {
		this->deltaTicks = 0;
		this->deltaProgress = 0;
		this->delta = count / 10;
		std::cout << taskName;
		Log::info() << " [" << deltaProgress * 10 << "%] ";
	}

	if (deltaTicks >= this->delta)
	{
		deltaProgress++;
		std::cout << " [" << deltaProgress * 10 << "%] ";
		std::cout.flush();
		Log::info() << " [" << deltaProgress * 10 << "%] ";
		this->deltaTicks = 0;

	}
	if ( ticks >= count -1  ) {

		string now = myPc.clock.now();
        Log::info() << now;
        std::cout << now << endl;
	}
	deltaTicks++;
}

<commit_msg>changed GetFileAttribute to GetFileAttributesA in abstractable.cc<commit_after>/**
   MiracleGrue - Model Generator for toolpathing. <http://www.grue.makerbot.com>
   Copyright (C) 2011 Far McKon <Far@makerbot.com>, Hugo Boyer (hugo@makerbot.com)

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

**/
#include "abstractable.h"

using namespace mgl;
using namespace std;

#include "log.h"

#ifdef __APPLE__
#include <CFBundle.h>
#endif

#ifdef WIN32
#include <Windows.h>
#include <Shlobj.h>
#else
#include <sys/types.h>
#include <pwd.h>
#endif

#include <fstream>

std::ostream &MyComputer::log()
{
    return cout;
}

#ifdef QT_CORE_LIB
int FileSystemAbstractor::guarenteeDirectoryExists(const char* )//pathname  )
{
    Log::info() << "not supported on QT" << endl;
    return -1;
#else
int FileSystemAbstractor::guarenteeDirectoryExists(const char* pathname)
{
    int status = 0;

#ifdef WIN32
        DWORD attrib = GetFileAttributesA(pathname);

        if (attrib == INVALID_FILE_ATTRIBUTES) {
            BOOL result = CreateDirectoryA(pathname, NULL);
            if (!result)
                status = -1; //creation fail
        }
        else if (!(attrib & FILE_ATTRIBUTE_DIRECTORY))
            status = -1;

#else //WIN32
        // mode_t does not work under QT
        mode_t mode =  (S_IREAD|S_IWRITE |S_IRGRP|S_IWGRP |S_IROTH);

		struct stat st;
		if(stat(pathname,&st) != 0){
			mode_t process_mask = umask(0);
			int result_code = mkdir(pathname, mode);
			umask(process_mask);
			if(result_code != 0)
				status = -1 ; //creation fail
		}
		else if (!S_ISDIR(st.st_mode))
			status = -1;
		return status;
#endif //!WIN32
#endif //!QT_CORE_LIB

}

string FileSystemAbstractor::pathJoin(string path, string filename) const
{
#ifdef WIN32
    return path  + "\\" + filename;
#else
	return path  + "/" + filename;
#endif
}

char FileSystemAbstractor::getPathSeparatorCharacter() const
{
#ifdef WIN32
    return '\\';
#else
    return '/'; // Linux & Mac, works on Windows most times
#endif
}

string FileSystemAbstractor::ExtractDirectory(const char *directoryPath) const
{
	const string path(directoryPath);
	return path.substr(0, path.find_last_of(getPathSeparatorCharacter()) + 1);
}

string FileSystemAbstractor::ExtractFilename(const char* filename) const
{
	std::string path(filename);
	return path.substr(path.find_last_of(getPathSeparatorCharacter()) + 1);
}

string FileSystemAbstractor::ChangeExtension(const char* filename, const char* extension) const
{
	const string path(filename);
	const string ext(extension);
	std::string filenameStr = ExtractFilename(path.c_str());
	return ExtractDirectory(path.c_str())
			+ filenameStr.substr(0, filenameStr.find_last_of('.')) + ext;
}

string FileSystemAbstractor::removeExtension(const char *filename) const
{
	const string path(filename);
	string filenameStr = ExtractFilename(path.c_str());
	return ExtractDirectory(path.c_str())
			+ filenameStr.substr(0, filenameStr.find_last_of('.'));
}

bool FileSystemAbstractor::fileReadable(const char *filename) const {
	ifstream testfile(filename, ifstream::in);
	bool readable = !testfile.fail();
	testfile.close();

	return readable;
}

string FileSystemAbstractor::getDataFile(const char *filename) const {
	string found = getUserDataFile(filename);
	if (found.length() > 0 && fileReadable(found.c_str()))
		return found;

	found = getSystemDataFile(filename);
	if (found.length() > 0 && fileReadable(found.c_str()))
		return found;

	return string();
}

string FileSystemAbstractor::getConfigFile(const char *filename) const {
	string found = getUserConfigFile(filename);
	if (found.length() > 0 && fileReadable(found.c_str()))
		return found;

	found = getSystemConfigFile(filename);
	if (found.length() > 0 && fileReadable(found.c_str()))
		return found;

	return string();
}

string FileSystemAbstractor::getUserDataFile(const char *filename) const {
#ifdef __APPLE__
	char pwbuff[1024];
	struct passwd pw;
	struct passwd *tempptr;
	if (getpwuid_r(getuid(), &pw, pwbuff, 1024, &tempptr) == 0) {
	   return pathJoin(pathJoin(string(pw.pw_dir),
								 "Library/Makerbot/Miracle-Grue"),
					   filename);
	}
	else {
		return string();
	}
#else
	/*other platforms should be fine putting user data files in the same
	  dir as user config files*/
	return getUserConfigFile(filename);
#endif
}

string FileSystemAbstractor::getSystemDataFile(const char *filename) const {
#ifdef __linux__
	return pathJoin(string("/usr/share/makerbot"), filename);
#else
	return getSystemConfigFile(filename);
#endif
}

string FileSystemAbstractor::getSystemConfigFile(const char *filename) const {
#ifdef WIN32
    char app_path[1024];

	GetModuleFileNameA(0, app_path, sizeof(app_path) - 1);

	// Extract directory
	std::string app_dir = ExtractDirectory(app_path);
	return pathJoin(app_dir, filename);

#elif defined __APPLE__
	CFBundleRef mainBundle;

	mainBundle = CFBundleGetMainBundle();
	if(!mainBundle)
		return string();

	CFURLRef resourceURL;
	resourceURL =
		CFBundleCopyResourceURL(mainBundle,
					CFStringCreateWithCString(NULL,
											  filename,
											  kCFStringEncodingASCII),

								NULL,
								NULL);

	if (!resourceURL)
		return string();

	char fileurl[1024];
	if(!CFURLGetFileSystemRepresentation(resourceURL,
										 true,
										 (UInt8*)
										 fileurl,
										 1024)) {
		return string();
	}

	return string(fileurl);
#else //linux

	return pathJoin(string("/etc/xdg/makerbot"), filename);
#endif
}

string FileSystemAbstractor::getUserConfigFile(const char *filename) const {
#ifdef WIN32
	char app_data[1024];
	if(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0,
								 app_data))) {
		return pathJoin(pathJoin(string(app_data), "Makerbot"),
						filename);
	}
#else //linux or apple
	char pwbuff[1024];
	struct passwd pw;
	struct passwd *tempptr;
	if (getpwuid_r(getuid(), &pw, pwbuff, 1024, &tempptr) == 0) {

#ifdef __APPLE__
		return pathJoin(pathJoin(string(pw.pw_dir),
								 "Library/Preferences/Makerbot/Miracle-Grue"),
						filename);
#else //linux
		return pathJoin(pathJoin(string(pw.pw_dir), ".config/makerbot"),
						filename);
#endif //linux
	}

#endif //win32

	return string();
}

ProgressLog::ProgressLog(unsigned int count)
    :ProgressBar(count,"")
{
	reset(count);
	std::cout << ":";

}

void ProgressLog::onTick(const char* taskName, unsigned int count, unsigned int ticks)
{
	if (ticks == 0) {
		this->deltaTicks = 0;
		this->deltaProgress = 0;
		this->delta = count / 10;
		std::cout << taskName;
		Log::info() << " [" << deltaProgress * 10 << "%] ";
	}

	if (deltaTicks >= this->delta)
	{
		deltaProgress++;
		std::cout << " [" << deltaProgress * 10 << "%] ";
		std::cout.flush();
		Log::info() << " [" << deltaProgress * 10 << "%] ";
		this->deltaTicks = 0;

	}
	if ( ticks >= count -1  ) {

		string now = myPc.clock.now();
        Log::info() << now;
        std::cout << now << endl;
	}
	deltaTicks++;
}

<|endoftext|>


<commit_before>#ifdef HAVE_NETWORKING
#include "hawknl/nl.h"
#endif
#include "network.h"
#include "globals.h"
#include <string>
#include <sstream>
#include <string.h>
#include "util/system.h"
#include "util/compress.h"

using namespace std;

/* TODO: Wrap open_sockets with a mutex */
namespace Network{

NetworkException::~NetworkException() throw (){
}

MessageEnd::MessageEnd(){
}

InvalidPortException::InvalidPortException( int port, const string message ):
NetworkException(""){
	ostringstream num;
	num << port;
	num << ". ";
	num << message;
	this->setMessage( "Invalid port " + num.str() );
}

Message::Message():
id((uint32_t) -1),
timestamp(0),
readFrom(0){
	memset(data, 0, sizeof(data));
	position = data;
}

Message::Message(const Message & m):
timestamp(m.timestamp),
readFrom(m.readFrom){
    memcpy( data, m.data, sizeof(data) );
    position = data;
    position += m.position - m.data;
    path = m.path;
    id = m.id;
}

Message & Message::operator=( const Message & m ){
    memcpy(data, m.data, sizeof(data));
    position = data;
    position += m.position - m.data;
    path = m.path;
    id = m.id;
    timestamp = m.timestamp;
    readFrom = m.readFrom;
    return *this;
}

Message::Message(Socket socket){
#ifdef HAVE_NETWORKING
    position = data;
    id = read32( socket );
    readBytes( socket, data, DATA_SIZE );
    int str = read16( socket );
    if ( str != -1 ){
        /* cap strings at 1024 bytes */
        char buf[1024];
        str = (signed)(sizeof( buf ) - 1) < str ? (signed)(sizeof(buf) - 1) : str;
        readBytes( socket, (uint8_t *) buf, str );
        buf[str] = 0;
        /* this is a string copy, not an assignment to a temporary pointer */
        this->path = buf;
    }
    timestamp = System::currentMicroseconds();
    readFrom = socket;
#endif
}

uint8_t * Message::dump( uint8_t * buffer ) const {
    *(uint32_t *) buffer = id;
    buffer += sizeof(id);
    memcpy( buffer, data, DATA_SIZE );
    buffer += DATA_SIZE;
    if ( path != "" ){
        *(uint16_t *) buffer = path.length() + 1;
        buffer += sizeof(uint16_t);
        memcpy( buffer, path.c_str(), path.length() + 1 );
        buffer += path.length() + 1;
    } else {
        *(uint16_t *) buffer = (uint16_t) -1;
        buffer += sizeof(uint16_t);
    }
    return buffer;
}

/*
template <typename M>
int messageSize(const M& message);
*/

/*
template <>
int messageSize<Message>(Message const & message){
    return message.size();
}

template <>
int messageSize<Message*>(Message* const & message){
    return message->size();
}
*/
static int messageSize(Message const & message){
    return message.size();
}

static int messageSize(Message* const & message){
    return message->size();
}

/*
template <class M>
uint8_t * messageDump(const M& message, uint8_t * buffer);

template <>
uint8_t * messageDump<Message>(const Message & message, uint8_t * buffer){
    return message.dump(buffer);
}

template <>
uint8_t * messageDump<Message*>(Message* const & message, uint8_t * buffer){
    return message->dump(buffer);
}
*/
static uint8_t * messageDump(const Message & message, uint8_t * buffer){
    return message.dump(buffer);
}

static uint8_t * messageDump(Message* const & message, uint8_t * buffer){
    return message->dump(buffer);
}

template <typename M>
static int totalSize(const vector<M> & messages){
    int size = 0;
    for (typename vector<M>::const_iterator it = messages.begin(); it != messages.end(); it++){
        // size += messageSize<M>(*it);
        size += messageSize(*it);
    }
    return size;
}

template <class M>
static void dump(const std::vector<M> & messages, uint8_t * buffer ){
    for (typename vector<M>::const_iterator it = messages.begin(); it != messages.end(); it++ ){
        buffer = messageDump(*it, buffer);
    }
}

#ifdef HAVE_NETWORKING
template <class M>
static void doSendAllMessages(const vector<M> & messages, Socket socket){
    int length = totalSize<M>(messages);
    uint8_t * data = new uint8_t[length];
    dump<M>(messages, data);
    // Compress::testCompression((unsigned char *) data, length);
    sendBytes(socket, data, length);
    delete[] data;
}

void sendAllMessages(const vector<Message> & messages, Socket socket){
    doSendAllMessages<Message>(messages, socket);
}

void sendAllMessages(const vector<Message*> & messages, Socket socket){
    doSendAllMessages<Message*>(messages, socket);
}
#endif

void Message::send( Socket socket ) const {
	/*
	send16( socket, id );
	sendBytes( socket, data, DATA_SIZE );
	if ( path != "" ){
		send16( socket, path.length() + 1 );
		sendStr( socket, path );
	} else {
		send16( socket, -1 );
	}
	*/
#ifdef HAVE_NETWORKING
	uint8_t * buffer = new uint8_t[ size() ];
	dump( buffer );
	sendBytes( socket, buffer, size() );
	delete[] buffer;
#endif
}

void Message::reset(){
    position = data;
}

Message & Message::operator<<(int x){
    if (position > data + DATA_SIZE - sizeof(uint16_t)){
        throw NetworkException("Tried to set too much data");
    }

    *(int16_t *) position = x;
    position += sizeof(int16_t);

    return *this;
}

Message & Message::operator<<(unsigned int x){
    if (position > data + DATA_SIZE - sizeof(uint32_t)){
        throw NetworkException("Tried to set too much data");
    }

    *(int32_t *) position = x;
    position += sizeof(int32_t);
    return *this;
}

Message & Message::operator>>(int & x){
    if (position > data + DATA_SIZE - sizeof(uint16_t)){
        throw NetworkException("Tried to read too much data");
    }

    x = *(int16_t *) position;
    position += sizeof(int16_t);
    return *this;
}

Message & Message::operator>>(unsigned int & x){
    if (position > data + DATA_SIZE - sizeof(uint32_t)){
        throw NetworkException("Tried to read too much data");
    }

    x = *(int32_t *) position;
    position += sizeof(int32_t);
    return *this;
}

Message & Message::operator<<( string p ){
    path = p;
    return *this;
}

int Message::size() const {
    return sizeof(id) + DATA_SIZE +
           (path != "" ? sizeof(uint16_t) + path.length() + 1 : sizeof(uint16_t));
}

#ifdef HAVE_NETWORKING

static string getHawkError(){
	return string(" HawkNL error: '") +
	       string( nlGetErrorStr( nlGetError() ) ) +
	       string( "' HawkNL system error: '" ) +
	       string( nlGetSystemErrorStr( nlGetSystemError() ) );
}

template<typename X>
static X readX(Socket socket){
	uint8_t data[ sizeof(X) ];
	readBytes( socket, data, sizeof(X) );
	return *(X *)data;
}

int16_t read16( Socket socket ){
    return readX<uint16_t>(socket);
    /*
	uint8_t data[ sizeof(uint16_t) ];
	readBytes( socket, data, sizeof(uint16_t) );
	return *(uint16_t *)data;
    */

	/*
	uint16_t b;
	int read = nlRead( socket, &b, sizeof(int16_t) );
	if ( read != sizeof(int16_t) ){
		throw NetworkException( string("Could not read 16 bits.") + getHawkError() );
	}
	return b;
	*/
}

int32_t read32( Socket socket ){
    return readX<uint32_t>(socket);
}

void send16( Socket socket, int16_t bytes ){
	/*
	if ( nlWrite( socket, &length, sizeof(int16_t) ) != sizeof(int16_t) ){
		throw NetworkException( string("Could not send 16 bits.") + getHawkError() );
	}
	*/
	sendBytes( socket, (uint8_t *) &bytes, sizeof(bytes) );
}

string readStr( Socket socket, const uint16_t length ){

	char buffer[ length + 1 ];
	NLint bytes = nlRead( socket, buffer, length );
	if ( bytes == NL_INVALID ){
		throw NetworkException( string("Could not read string.") + getHawkError() );
	}
	buffer[ length ] = 0;
	bytes += 1;
	return string( buffer );

}

void sendStr( Socket socket, const string & str ){
	if ( nlWrite( socket, str.c_str(), str.length() + 1 ) != (signed)(str.length() + 1) ){
		throw NetworkException( string("Could not write string.") + getHawkError() );
	}
}

void sendBytes( Socket socket, const uint8_t * data, int length ){
	const uint8_t * position = data;
	int written = 0;
	while ( written < length ){
		/* put htons here for endianess compatibility */
		int bytes = nlWrite( socket, position, length - written );
		if ( bytes == NL_INVALID ){
			throw NetworkException( string("Could not send bytes.") + getHawkError() );
		}
		written += bytes;
		position += bytes;
	}
}

void readBytes( Socket socket, uint8_t * data, int length ){
	uint8_t * position = data;
	int read = 0;
	while ( read < length ){
		/* put htons here for endianess compatibility */
		int bytes = nlRead( socket, position, length - read );
		if ( bytes == NL_INVALID ){
                    switch (nlGetError()){
                        case NL_MESSAGE_END : throw MessageEnd();
                        default : throw NetworkException(string("Could not read bytes.") + getHawkError());
                    }
		}
		read += bytes;
		position += bytes;
	}
}

Socket open( int port ) throw (InvalidPortException){
	// NLsocket server = nlOpen( port, NL_RELIABLE_PACKETS );
	Global::debug(1, "network") << "Attemping to open port " << port << endl;
	Socket server = nlOpen( port, NL_RELIABLE );
        /* server will either be NL_INVALID (-1) or some low integer. hawknl
         * sockets are mapped internally to real sockets, so don't be surprised
         * if you get a socket back like 0.
         */
	if ( server == NL_INVALID ){
		throw InvalidPortException(port, nlGetSystemErrorStr(nlGetSystemError()));
	}
        Global::debug(1, "network") << "Successfully opened a socket: " << server << endl;
	open_sockets.push_back( server );
	return server;
}

Socket connect( string server, int port ) throw ( NetworkException ) {
	NLaddress address;
	nlGetAddrFromName( server.c_str(), &address );
	nlSetAddrPort( &address, port );
	Socket socket = open( 0 );
	if ( nlConnect( socket, &address ) == NL_FALSE ){
		close( socket );
		throw NetworkException( "Could not connect" );
	}
	return socket;
}

void close( Socket s ){
	for ( vector< Socket >::iterator it = open_sockets.begin(); it != open_sockets.end(); ){
		if ( *it == s ){
			Global::debug(1, "network") << "Closing socket " << s << endl;
			nlClose( *it );
			Global::debug(1, "network") << "Closed" << endl;
			it = open_sockets.erase( it );
		} else {
			it++;
		}
	}
}

void closeAll(){
	Global::debug(0, "network") << "Closing all sockets" << std::endl;
	for ( vector< Socket >::iterator it = open_sockets.begin(); it != open_sockets.end(); it++ ){
		nlClose( *it );
	}
	open_sockets.clear();
}

void init(){
	nlInit();
	nlSelectNetwork( NL_IP );
	nlEnable( NL_BLOCKING_IO );
	// nlDisable( NL_BLOCKING_IO );
}

void blocking( bool b ){
	if ( b ){
		nlEnable( NL_BLOCKING_IO );
	} else {
		nlDisable( NL_BLOCKING_IO );
	}
}

void listen( Socket s ) throw( NetworkException ){
	if ( nlListen( s ) == NL_FALSE ){
		throw CannotListenException( string(nlGetSystemErrorStr( nlGetSystemError() )) );
	}
}

Socket accept( Socket s ) throw( NetworkException ){
	Socket connection = nlAcceptConnection( s );
	if ( connection == NL_INVALID ){
		/*
		if ( nlGetError() == NL_NO_PENDING ){
			error = NO_CONNECTIONS_PENDING;
		} else {
			error = NETWORK_ERROR;
		}
		return s;
		*/
		if ( nlGetError() == NL_NO_PENDING ){
			throw NoConnectionsPendingException();
		}
		throw NetworkException("Could not accept connection");
	}
	open_sockets.push_back( connection );
	return connection;
}

void shutdown(){
	nlShutdown();
}

#endif

}
<commit_msg>avoid breaking gcc alias rules<commit_after>#ifdef HAVE_NETWORKING
#include "hawknl/nl.h"
#endif
#include "network.h"
#include "globals.h"
#include <string>
#include <sstream>
#include <string.h>
#include "util/system.h"
#include "util/compress.h"

using namespace std;

/* TODO: Wrap open_sockets with a mutex */
namespace Network{

NetworkException::~NetworkException() throw (){
}

MessageEnd::MessageEnd(){
}

InvalidPortException::InvalidPortException( int port, const string message ):
NetworkException(""){
	ostringstream num;
	num << port;
	num << ". ";
	num << message;
	this->setMessage( "Invalid port " + num.str() );
}

Message::Message():
id((uint32_t) -1),
timestamp(0),
readFrom(0){
	memset(data, 0, sizeof(data));
	position = data;
}

Message::Message(const Message & m):
timestamp(m.timestamp),
readFrom(m.readFrom){
    memcpy( data, m.data, sizeof(data) );
    position = data;
    position += m.position - m.data;
    path = m.path;
    id = m.id;
}

Message & Message::operator=( const Message & m ){
    memcpy(data, m.data, sizeof(data));
    position = data;
    position += m.position - m.data;
    path = m.path;
    id = m.id;
    timestamp = m.timestamp;
    readFrom = m.readFrom;
    return *this;
}

Message::Message(Socket socket){
#ifdef HAVE_NETWORKING
    position = data;
    id = read32( socket );
    readBytes( socket, data, DATA_SIZE );
    int str = read16( socket );
    if ( str != -1 ){
        /* cap strings at 1024 bytes */
        char buf[1024];
        str = (signed)(sizeof( buf ) - 1) < str ? (signed)(sizeof(buf) - 1) : str;
        readBytes( socket, (uint8_t *) buf, str );
        buf[str] = 0;
        /* this is a string copy, not an assignment to a temporary pointer */
        this->path = buf;
    }
    timestamp = System::currentMicroseconds();
    readFrom = socket;
#endif
}

uint8_t * Message::dump( uint8_t * buffer ) const {
    *(uint32_t *) buffer = id;
    buffer += sizeof(id);
    memcpy( buffer, data, DATA_SIZE );
    buffer += DATA_SIZE;
    if ( path != "" ){
        *(uint16_t *) buffer = path.length() + 1;
        buffer += sizeof(uint16_t);
        memcpy( buffer, path.c_str(), path.length() + 1 );
        buffer += path.length() + 1;
    } else {
        *(uint16_t *) buffer = (uint16_t) -1;
        buffer += sizeof(uint16_t);
    }
    return buffer;
}

/*
template <typename M>
int messageSize(const M& message);
*/

/*
template <>
int messageSize<Message>(Message const & message){
    return message.size();
}

template <>
int messageSize<Message*>(Message* const & message){
    return message->size();
}
*/
static int messageSize(Message const & message){
    return message.size();
}

static int messageSize(Message* const & message){
    return message->size();
}

/*
template <class M>
uint8_t * messageDump(const M& message, uint8_t * buffer);

template <>
uint8_t * messageDump<Message>(const Message & message, uint8_t * buffer){
    return message.dump(buffer);
}

template <>
uint8_t * messageDump<Message*>(Message* const & message, uint8_t * buffer){
    return message->dump(buffer);
}
*/
static uint8_t * messageDump(const Message & message, uint8_t * buffer){
    return message.dump(buffer);
}

static uint8_t * messageDump(Message* const & message, uint8_t * buffer){
    return message->dump(buffer);
}

template <typename M>
static int totalSize(const vector<M> & messages){
    int size = 0;
    for (typename vector<M>::const_iterator it = messages.begin(); it != messages.end(); it++){
        // size += messageSize<M>(*it);
        size += messageSize(*it);
    }
    return size;
}

template <class M>
static void dump(const std::vector<M> & messages, uint8_t * buffer ){
    for (typename vector<M>::const_iterator it = messages.begin(); it != messages.end(); it++ ){
        buffer = messageDump(*it, buffer);
    }
}

#ifdef HAVE_NETWORKING
template <class M>
static void doSendAllMessages(const vector<M> & messages, Socket socket){
    int length = totalSize<M>(messages);
    uint8_t * data = new uint8_t[length];
    dump<M>(messages, data);
    // Compress::testCompression((unsigned char *) data, length);
    sendBytes(socket, data, length);
    delete[] data;
}

void sendAllMessages(const vector<Message> & messages, Socket socket){
    doSendAllMessages<Message>(messages, socket);
}

void sendAllMessages(const vector<Message*> & messages, Socket socket){
    doSendAllMessages<Message*>(messages, socket);
}
#endif

void Message::send( Socket socket ) const {
	/*
	send16( socket, id );
	sendBytes( socket, data, DATA_SIZE );
	if ( path != "" ){
		send16( socket, path.length() + 1 );
		sendStr( socket, path );
	} else {
		send16( socket, -1 );
	}
	*/
#ifdef HAVE_NETWORKING
	uint8_t * buffer = new uint8_t[ size() ];
	dump( buffer );
	sendBytes( socket, buffer, size() );
	delete[] buffer;
#endif
}

void Message::reset(){
    position = data;
}

Message & Message::operator<<(int x){
    if (position > data + DATA_SIZE - sizeof(uint16_t)){
        throw NetworkException("Tried to set too much data");
    }

    *(int16_t *) position = x;
    position += sizeof(int16_t);

    return *this;
}

Message & Message::operator<<(unsigned int x){
    if (position > data + DATA_SIZE - sizeof(uint32_t)){
        throw NetworkException("Tried to set too much data");
    }

    *(int32_t *) position = x;
    position += sizeof(int32_t);
    return *this;
}

Message & Message::operator>>(int & x){
    if (position > data + DATA_SIZE - sizeof(uint16_t)){
        throw NetworkException("Tried to read too much data");
    }

    x = *(int16_t *) position;
    position += sizeof(int16_t);
    return *this;
}

Message & Message::operator>>(unsigned int & x){
    if (position > data + DATA_SIZE - sizeof(uint32_t)){
        throw NetworkException("Tried to read too much data");
    }

    x = *(int32_t *) position;
    position += sizeof(int32_t);
    return *this;
}

Message & Message::operator<<( string p ){
    path = p;
    return *this;
}

int Message::size() const {
    return sizeof(id) + DATA_SIZE +
           (path != "" ? sizeof(uint16_t) + path.length() + 1 : sizeof(uint16_t));
}

#ifdef HAVE_NETWORKING

static string getHawkError(){
	return string(" HawkNL error: '") +
	       string( nlGetErrorStr( nlGetError() ) ) +
	       string( "' HawkNL system error: '" ) +
	       string( nlGetSystemErrorStr( nlGetSystemError() ) );
}

template<typename X>
static X readX(Socket socket){
    X data;
    readBytes(socket, (uint8_t*) &data, sizeof(X));
    return data;
}

int16_t read16( Socket socket ){
    return readX<uint16_t>(socket);
    /*
	uint8_t data[ sizeof(uint16_t) ];
	readBytes( socket, data, sizeof(uint16_t) );
	return *(uint16_t *)data;
    */

	/*
	uint16_t b;
	int read = nlRead( socket, &b, sizeof(int16_t) );
	if ( read != sizeof(int16_t) ){
		throw NetworkException( string("Could not read 16 bits.") + getHawkError() );
	}
	return b;
	*/
}

int32_t read32( Socket socket ){
    return readX<uint32_t>(socket);
}

void send16( Socket socket, int16_t bytes ){
	/*
	if ( nlWrite( socket, &length, sizeof(int16_t) ) != sizeof(int16_t) ){
		throw NetworkException( string("Could not send 16 bits.") + getHawkError() );
	}
	*/
	sendBytes( socket, (uint8_t *) &bytes, sizeof(bytes) );
}

string readStr( Socket socket, const uint16_t length ){

	char buffer[ length + 1 ];
	NLint bytes = nlRead( socket, buffer, length );
	if ( bytes == NL_INVALID ){
		throw NetworkException( string("Could not read string.") + getHawkError() );
	}
	buffer[ length ] = 0;
	bytes += 1;
	return string( buffer );

}

void sendStr( Socket socket, const string & str ){
	if ( nlWrite( socket, str.c_str(), str.length() + 1 ) != (signed)(str.length() + 1) ){
		throw NetworkException( string("Could not write string.") + getHawkError() );
	}
}

void sendBytes( Socket socket, const uint8_t * data, int length ){
	const uint8_t * position = data;
	int written = 0;
	while ( written < length ){
		/* put htons here for endianess compatibility */
		int bytes = nlWrite( socket, position, length - written );
		if ( bytes == NL_INVALID ){
			throw NetworkException( string("Could not send bytes.") + getHawkError() );
		}
		written += bytes;
		position += bytes;
	}
}

void readBytes( Socket socket, uint8_t * data, int length ){
	uint8_t * position = data;
	int read = 0;
	while ( read < length ){
		/* put htons here for endianess compatibility */
		int bytes = nlRead( socket, position, length - read );
		if ( bytes == NL_INVALID ){
                    switch (nlGetError()){
                        case NL_MESSAGE_END : throw MessageEnd();
                        default : throw NetworkException(string("Could not read bytes.") + getHawkError());
                    }
		}
		read += bytes;
		position += bytes;
	}
}

Socket open( int port ) throw (InvalidPortException){
	// NLsocket server = nlOpen( port, NL_RELIABLE_PACKETS );
	Global::debug(1, "network") << "Attemping to open port " << port << endl;
	Socket server = nlOpen( port, NL_RELIABLE );
        /* server will either be NL_INVALID (-1) or some low integer. hawknl
         * sockets are mapped internally to real sockets, so don't be surprised
         * if you get a socket back like 0.
         */
	if ( server == NL_INVALID ){
		throw InvalidPortException(port, nlGetSystemErrorStr(nlGetSystemError()));
	}
        Global::debug(1, "network") << "Successfully opened a socket: " << server << endl;
	open_sockets.push_back( server );
	return server;
}

Socket connect( string server, int port ) throw ( NetworkException ) {
	NLaddress address;
	nlGetAddrFromName( server.c_str(), &address );
	nlSetAddrPort( &address, port );
	Socket socket = open( 0 );
	if ( nlConnect( socket, &address ) == NL_FALSE ){
		close( socket );
		throw NetworkException( "Could not connect" );
	}
	return socket;
}

void close( Socket s ){
	for ( vector< Socket >::iterator it = open_sockets.begin(); it != open_sockets.end(); ){
		if ( *it == s ){
			Global::debug(1, "network") << "Closing socket " << s << endl;
			nlClose( *it );
			Global::debug(1, "network") << "Closed" << endl;
			it = open_sockets.erase( it );
		} else {
			it++;
		}
	}
}

void closeAll(){
	Global::debug(0, "network") << "Closing all sockets" << std::endl;
	for ( vector< Socket >::iterator it = open_sockets.begin(); it != open_sockets.end(); it++ ){
		nlClose( *it );
	}
	open_sockets.clear();
}

void init(){
	nlInit();
	nlSelectNetwork( NL_IP );
	nlEnable( NL_BLOCKING_IO );
	// nlDisable( NL_BLOCKING_IO );
}

void blocking( bool b ){
	if ( b ){
		nlEnable( NL_BLOCKING_IO );
	} else {
		nlDisable( NL_BLOCKING_IO );
	}
}

void listen( Socket s ) throw( NetworkException ){
	if ( nlListen( s ) == NL_FALSE ){
		throw CannotListenException( string(nlGetSystemErrorStr( nlGetSystemError() )) );
	}
}

Socket accept( Socket s ) throw( NetworkException ){
	Socket connection = nlAcceptConnection( s );
	if ( connection == NL_INVALID ){
		/*
		if ( nlGetError() == NL_NO_PENDING ){
			error = NO_CONNECTIONS_PENDING;
		} else {
			error = NETWORK_ERROR;
		}
		return s;
		*/
		if ( nlGetError() == NL_NO_PENDING ){
			throw NoConnectionsPendingException();
		}
		throw NetworkException("Could not accept connection");
	}
	open_sockets.push_back( connection );
	return connection;
}

void shutdown(){
	nlShutdown();
}

#endif

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include <iostream>
#include <sstream>

#include "db/rt/Exception.h"
#include "db/test/Test.h"
#include "db/test/Tester.h"
#include "db/test/TestRunner.h"
#include "db/config/ConfigManager.h"
#include "db/data/json/JsonWriter.h"

using namespace std;
using namespace db::rt;
using namespace db::test;
using namespace db::config;

void runConfigManagerTest(TestRunner& tr)
{
   tr.group("ConfigManager");
#if 0
   tr.test("init");
   {
      DynamicObject expect;
      expect->setType(Map);
      ConfigManager cm;
      assertDynoCmp(cm.getConfig(), expect);
   }
   tr.passIfNoException();

   tr.test("init & clear");
   {
      DynamicObject expect;
      expect->setType(Map);
      ConfigManager cm;
      cm.clear();
      assertDynoCmp(cm.getConfig(), expect);
   }
   tr.passIfNoException();

   tr.test("1 config");
   {
      DynamicObject expect;
      expect->setType(Map);
      expect["a"] = 0;
      ConfigManager cm;
      DynamicObject a;
      a["a"] = 0;
      assert(cm.addConfig(a));
      assertNoException();
      assertDynoCmp(cm.getConfig(), expect);
   }
   tr.passIfNoException();

   tr.test("clear & 1 config");
   {
      DynamicObject expect;
      expect->setType(Map);
      expect["a"] = 0;
      ConfigManager cm;
      cm.clear();
      DynamicObject a;
      a["a"] = 0;
      assert(cm.addConfig(a));
      assertNoException();
      assertDynoCmp(cm.getConfig(), expect);
   }
   tr.passIfNoException();

   tr.test("config change");
   {
      ConfigManager cm;
      DynamicObject a;
      a["a"] = 0;
      assert(cm.addConfig(a));
      assertNoException();
      assertDynoCmp(cm.getConfig(), a);
      cm.getConfig()["a"] = 1;
      DynamicObject expect;
      expect["a"] = 1;
      assert(cm.getConfig() != a);
      assertDynoCmp(cm.getConfig(), expect);
   }
   tr.passIfNoException();

   tr.test("add");
   {
      DynamicObject expect;
      expect["a"] = 0;
      expect["b"] = 1;
      expect["c"] = 2;
      ConfigManager cm;
      DynamicObject a;
      a["a"] = 0;
      DynamicObject b;
      b["b"] = 1;
      DynamicObject c;
      c["c"] = 2;
      assert(cm.addConfig(a));
      assertNoException();
      assert(cm.addConfig(b));
      assertNoException();
      assert(cm.addConfig(c));
      assertNoException();
      assertDynoCmp(cm.getConfig(), expect);
   }
   tr.passIfNoException();

   tr.test("bad remove");
   {
      ConfigManager cm;
      assert(!cm.removeConfig(0));
      assertException();
      Exception::clearLast();
   }
   tr.passIfNoException();

   tr.test("remove");
   {
      DynamicObject expect;
      expect["a"] = 0;
      expect["b"] = 1;
      expect["c"] = 2;
      ConfigManager cm;
      DynamicObject a;
      a["a"] = 0;
      DynamicObject b;
      b["b"] = 1;
      DynamicObject c;
      c["c"] = 2;
      ConfigManager::ConfigId id;
      assert(cm.addConfig(a));
      assertNoException();
      assert(cm.addConfig(b, ConfigManager::Default, &id));
      assertNoException();
      assert(cm.addConfig(c));
      assertNoException();
      assertDynoCmp(cm.getConfig(), expect);
      DynamicObject expect2;
      expect2["a"] = 0;
      expect2["c"] = 2;
      assert(cm.removeConfig(id));
      assertDynoCmp(cm.getConfig(), expect2);
   }
   tr.passIfNoException();

   tr.test("update");
   {
      ConfigManager cm;
      DynamicObject expect;
      expect["a"] = 0;
      DynamicObject a;
      a["a"] = 0;
      assert(cm.addConfig(a));
      assertNoException();
      assertDynoCmp(cm.getConfig(), expect);
      DynamicObject expect2;
      expect2["a"] = 1;
      a["a"] = 1;
      assert(cm.getConfig() != expect2);
      cm.update();
      assertNoException();
      assertDynoCmp(cm.getConfig(), expect2);
   }
   tr.passIfNoException();

   tr.test("set");
   {
      ConfigManager cm;
      DynamicObject expect;
      expect["a"] = 0;
      DynamicObject a;
      a["a"] = 0;
      ConfigManager::ConfigId id;
      assert(cm.addConfig(a, ConfigManager::Default, &id));
      assertNoException();
      assertDynoCmp(cm.getConfig(), expect);
      DynamicObject expect2;
      expect2["b"] = 0;
      DynamicObject b;
      b["b"] = 0;
      cm.setConfig(id, b);
      assertDynoCmp(cm.getConfig(), expect2);
   }
   tr.passIfNoException();

   tr.test("get");
   {
      ConfigManager cm;
      DynamicObject expect;
      expect["a"] = 0;
      DynamicObject a;
      a["a"] = 0;
      ConfigManager::ConfigId id;
      assert(cm.addConfig(a, ConfigManager::Default, &id));
      assertNoException();
      assertDynoCmp(cm.getConfig(), expect);
      DynamicObject b;
      assert(cm.getConfig(id, b));
      assertDynoCmp(b, expect);
   }
   tr.passIfNoException();

   tr.test("map changes");
   {
      ConfigManager cm;
      DynamicObject a;
      a["a"] = 0;
      a["b"] = 0;
      assert(cm.addConfig(a));
      assertNoException();
      cm.getConfig()["a"] = 1;
      DynamicObject expect;
      expect["a"] = 1;
      DynamicObject changes;
      cm.getChanges(changes);
      assertDynoCmp(changes, expect);
   }
   tr.passIfNoException();

   tr.test("deep map changes");
   {
      ConfigManager cm;
      DynamicObject a;
      a["a"]["b"] = 0;
      a["a"]["c"] = 0;
      assert(cm.addConfig(a));
      assertNoException();
      cm.getConfig()["a"]["c"] = 1;
      cm.getConfig()["d"] = 0;
      DynamicObject expect;
      expect["a"]["c"] = 1;
      expect["d"] = 0;
      DynamicObject changes;
      cm.getChanges(changes);
      assertDynoCmp(changes, expect);
   }
   tr.passIfNoException();

   tr.test("array changes");
   {
      ConfigManager cm;
      DynamicObject a;
      a[0] = 10;
      a[1] = 11;
      a[2] = 12;
      assert(cm.addConfig(a));
      assertNoException();
      cm.getConfig()[1] = 21;
      DynamicObject expect;
      expect[0] = "__default__";
      expect[1] = 21;
      expect[2] = "__default__";
      DynamicObject changes;
      cm.getChanges(changes);
      assertDynoCmp(changes, expect);
   }
   tr.passIfNoException();

   tr.test("bigger array changes");
   {
      ConfigManager cm;
      DynamicObject a;
      a[0] = 10;
      a[1] = 11;
      assert(cm.addConfig(a));
      assertNoException();
      cm.getConfig()[2] = 22;
      DynamicObject expect;
      expect[0] = "__default__";
      expect[1] = "__default__";
      expect[2] = 22;
      DynamicObject changes;
      cm.getChanges(changes);
      assertDynoCmp(changes, expect);
   }
   tr.passIfNoException();

   tr.test("system vs user changes");
   {
      ConfigManager cm;

      // system
      DynamicObject a;
      a[0] = 10;
      a[1] = 11;
      assert(cm.addConfig(a, ConfigManager::Default));
      assertNoException();

      // user
      DynamicObject b;
      b[0] = 20;
      b[1] = 21;
      assert(cm.addConfig(b, ConfigManager::Custom));
      assertNoException();

      // custom
      cm.getConfig()[1] = 31;

      {
         // Changes from system configs
         DynamicObject expect;
         expect[0] = 20;
         expect[1] = 31;
         DynamicObject changes;
         cm.getChanges(changes);
         assertDynoCmp(changes, expect);
      }

      {
         // Changes from system+user configs
         DynamicObject expect;
         expect[0] = "__default__";
         expect[1] = 31;
         DynamicObject changes;
         cm.getChanges(changes, ConfigManager::All);
         assertDynoCmp(changes, expect);
      }
   }
   tr.passIfNoException();

   tr.test("default value");
   {
      ConfigManager cm;
      DynamicObject a;
      a = 1;
      assert(cm.addConfig(a));
      assertNoException();
      DynamicObject b;
      b = "__default__";
      assert(cm.addConfig(b));
      assertNoException();
      DynamicObject expect;
      expect = 1;
      assertDynoCmp(cm.getConfig(), expect);
   }
   tr.passIfNoException();

   tr.test("default values");
   {
      ConfigManager cm;
      DynamicObject a;
      a[0] = 10;
      a[1] = 11;
      a[2]["0"] = 120;
      a[2]["1"] = 121;
      assert(cm.addConfig(a));
      assertNoException();
      DynamicObject b;
      b[0] = "__default__";
      b[1] = 21;
      b[2]["0"] = "__default__";
      b[2]["1"] = 221;
      assert(cm.addConfig(b));
      assertNoException();
      DynamicObject expect;
      expect[0] = 10;
      expect[1] = 21;
      expect[2]["0"] = 120;
      expect[2]["1"] = 221;
      assertDynoCmp(cm.getConfig(), expect);
   }
   tr.passIfNoException();

   tr.test("user preferences");
   {
      ConfigManager cm;

      // node
      // built in or loaded defaults
      DynamicObject nodec;
      nodec["node"]["host"] = "localhost";
      nodec["node"]["port"] = 19100;
      nodec["node"]["modulePath"] = "/usr/lib/bitmunk/modules";
      nodec["node"]["userModulePath"] = "~/.bitmunk/modules";
      assert(cm.addConfig(nodec));
      assertNoException();

      // user
      // loaded defaults
      DynamicObject userc;
      userc["node"]["port"] = 19100;
      userc["node"]["comment"] = "My precious...";
      assert(cm.addConfig(userc, ConfigManager::Custom));
      assertNoException();

      // user makes changes during runtime
      DynamicObject c = cm.getConfig();
      c["node"]["port"] = 19200;
      c["node"]["userModulePath"] = "~/.bitmunk/modules:~/.bitmunk/modules-dev";
      c["node"][ConfigManager::TMP]["not in changes"] = true;

      // get the changes from defaults to current config
      // serialize this to disk as needed
      DynamicObject changes;
      cm.getChanges(changes);

      // check it's correct
      DynamicObject expect;
      expect["node"]["port"] = 19200;
      expect["node"]["comment"] = "My precious...";
      expect["node"]["userModulePath"] = "~/.bitmunk/modules:~/.bitmunk/modules-dev";
      // NOTE: will not have TMP var
      assertDynoCmp(changes, expect);
   }
   tr.passIfNoException();

   tr.test("versioning");
   {
      ConfigManager cm;

      cm.getVersions()->clear();
      Config c;
      assert(cm.addConfig(c));
      assertNoException();

      cm.addVersion("1");
      assert(!cm.addConfig(c));
      assertException();
      Exception::clearLast();

      c[ConfigManager::VERSION] = "2";
      assert(!cm.addConfig(c));
      assertException();
      Exception::clearLast();

      c[ConfigManager::VERSION] = "1";
      assert(cm.addConfig(c));
      assertNoException();

      c[ConfigManager::VERSION] = "2";
      cm.addVersion("2");
      assert(cm.addConfig(c));
      assertNoException();
   }
   tr.passIfNoException();

   tr.test("empty array & map");
   {
      ConfigManager cm;
      DynamicObject a;
      a[0]->setType(Array);
      a[1]->setType(Map);
      assert(cm.addConfig(a));
      assertNoException();
      DynamicObject expect;
      expect[0]->setType(Array);
      expect[1]->setType(Map);
      assertDynoCmp(cm.getConfig(), expect);
   }
   tr.passIfNoException();
#endif
   tr.ungroup();
}

class DbConfigTester : public db::test::Tester
{
public:
   DbConfigTester()
   {
      setName("config");
   }

   /**
    * Run automatic unit tests.
    */
   virtual int runAutomaticTests(TestRunner& tr)
   {
      runConfigManagerTest(tr);
      return 0;
   }

   /**
    * Runs interactive unit tests.
    */
   virtual int runInteractiveTests(TestRunner& tr)
   {
      return 0;
   }
};

#ifndef DB_TEST_NO_MAIN
DB_TEST_MAIN(DbConfigTester)
#endif
<commit_msg>Fix tests for new ConfigManager API.<commit_after>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include <iostream>
#include <sstream>

#include "db/rt/Exception.h"
#include "db/test/Test.h"
#include "db/test/Tester.h"
#include "db/test/TestRunner.h"
#include "db/config/ConfigManager.h"
#include "db/data/json/JsonWriter.h"

using namespace std;
using namespace db::rt;
using namespace db::test;
using namespace db::config;

void runConfigManagerTest(TestRunner& tr)
{
   tr.group("ConfigManager");

   tr.test("init");
   {
      DynamicObject expect;
      expect->setType(Map);
      ConfigManager cm;
      Config cfg;
      cfg[ConfigManager::ID] = "config";
      cfg[ConfigManager::MERGE]->setType(Map);
      assert(cm.addConfig(cfg));
      assertDynoCmp(cm.getConfig("config", true), cfg);
      assertDynoCmp(cm.getConfig("config", false), expect);
      assertDynoCmp(cm.getConfig("config"), expect);
   }
   tr.passIfNoException();

   tr.test("init & clear");
   {
      DynamicObject expect;
      expect->setType(Map);
      ConfigManager cm;
      Config cfg;
      cfg[ConfigManager::ID] = "config";
      cfg[ConfigManager::MERGE]->setType(Map);
      assert(cm.addConfig(cfg));
      cm.clear();
      Config cfg2 = cm.getConfig("config");
      assert(cfg2.isNull());
   }
   tr.passIfException();

   tr.test("1 config");
   {
      DynamicObject expect;
      expect->setType(Map);
      expect["a"] = 0;
      ConfigManager cm;
      Config cfg;
      cfg[ConfigManager::ID] = "config";
      cfg[ConfigManager::MERGE]["a"] = 0;
      assert(cm.addConfig(cfg));
      assertNoException();
      assertDynoCmp(cm.getConfig("config"), expect);
   }
   tr.passIfNoException();

   tr.test("config change");
   {
      ConfigManager cm;
      Config cfg;
      cfg[ConfigManager::ID] = "config";
      cfg[ConfigManager::MERGE]["a"] = 0;
      assert(cm.addConfig(cfg));
      DynamicObject a;
      a["a"] = 0;
      assertDynoCmp(cm.getConfig("config"), a);
      Config change = cm.getConfig("config", true);
      change[ConfigManager::MERGE]["a"] = 1;
      assert(cm.setConfig(change));
      DynamicObject expect;
      expect["a"] = 1;
      assert(cm.getConfig("config") != a);
      assertDynoCmp(cm.getConfig("config"), expect);
   }
   tr.passIfNoException();

   tr.test("add");
   {
      DynamicObject expect;
      expect["a"] = 0;
      expect["b"] = 1;
      expect["c"] = 2;
      ConfigManager cm;
      Config a;
      a[ConfigManager::ID] = "config";
      a[ConfigManager::MERGE]["a"] = 0;
      Config b;
      b[ConfigManager::ID] = "config";
      b[ConfigManager::MERGE]["b"] = 1;
      Config c;
      c[ConfigManager::ID] = "config";
      c[ConfigManager::MERGE]["c"] = 2;
      assert(cm.addConfig(a));
      assertNoException();
      assert(cm.addConfig(b));
      assertNoException();
      assert(cm.addConfig(c));
      assertNoException();
      assertDynoCmp(cm.getConfig("config"), expect);
   }
   tr.passIfNoException();

   tr.test("bad remove");
   {
      ConfigManager cm;
      assert(!cm.removeConfig("error"));
      assertException();
      Exception::clearLast();
   }
   tr.passIfNoException();

   tr.test("remove");
   {
      DynamicObject expect;
      expect["a"] = 0;
      expect["b"] = 1;
      expect["c"] = 2;
      ConfigManager cm;
      Config a;
      a[ConfigManager::ID] = "config a";
      a[ConfigManager::GROUP] = "group";
      a[ConfigManager::MERGE]["a"] = 0;
      Config b;
      b[ConfigManager::ID] = "config b";
      b[ConfigManager::GROUP] = "group";
      b[ConfigManager::MERGE]["b"] = 1;
      Config c;
      c[ConfigManager::ID] = "config c";
      c[ConfigManager::GROUP] = "group";
      c[ConfigManager::MERGE]["c"] = 2;
      assert(cm.addConfig(a));
      assertNoException();
      assert(cm.addConfig(b));
      assertNoException();
      assert(cm.addConfig(c));
      assertNoException();
      assertDynoCmp(cm.getConfig("group"), expect);
      DynamicObject expect2;
      expect2["a"] = 0;
      expect2["c"] = 2;
      assert(cm.removeConfig("config b"));
      assertDynoCmp(cm.getConfig("group"), expect2);
   }
   tr.passIfNoException();

   tr.test("default value");
   {
      ConfigManager cm;
      Config a;
      a[ConfigManager::ID] = "config a";
      a[ConfigManager::MERGE] = 1;
      assert(cm.addConfig(a));
      assertNoException();
      Config b;
      b[ConfigManager::ID] = "config b";
      b[ConfigManager::PARENT] = "config a";
      b[ConfigManager::MERGE] = "__default__";
      assert(cm.addConfig(b));
      assertNoException();
      DynamicObject expect;
      expect = 1;
      assertDynoCmp(cm.getConfig("config b"), expect);
   }
   tr.passIfNoException();

   tr.test("default values");
   {
      ConfigManager cm;
      Config cfga;
      cfga[ConfigManager::ID] = "config a";
      Config& a = cfga[ConfigManager::MERGE];
      a[0] = 10;
      a[1] = 11;
      a[2]["0"] = 120;
      a[2]["1"] = 121;
      assert(cm.addConfig(cfga));
      assertNoException();
      Config cfgb;
      cfgb[ConfigManager::ID] = "config b";
      cfgb[ConfigManager::PARENT] = "config a";
      Config& b = cfgb[ConfigManager::MERGE];
      b[0] = "__default__";
      b[1] = 21;
      b[2]["0"] = "__default__";
      b[2]["1"] = 221;
      assert(cm.addConfig(cfgb));
      assertNoException();
      DynamicObject expect;
      expect[0] = 10;
      expect[1] = 21;
      expect[2]["0"] = 120;
      expect[2]["1"] = 221;
      assertDynoCmp(cm.getConfig("config b"), expect);
   }
   tr.passIfNoException();

#if 0
   tr.test("user preferences");
   {
      ConfigManager cm;

      // node
      // built in or loaded defaults
      DynamicObject nodec;
      nodec["node"]["host"] = "localhost";
      nodec["node"]["port"] = 19100;
      nodec["node"]["modulePath"] = "/usr/lib/bitmunk/modules";
      nodec["node"]["userModulePath"] = "~/.bitmunk/modules";
      assert(cm.addConfig(nodec));
      assertNoException();

      // user
      // loaded defaults
      DynamicObject userc;
      userc["node"]["port"] = 19100;
      userc["node"]["comment"] = "My precious...";
      assert(cm.addConfig(userc, ConfigManager::Custom));
      assertNoException();

      // user makes changes during runtime
      DynamicObject c = cm.getConfig();
      c["node"]["port"] = 19200;
      c["node"]["userModulePath"] = "~/.bitmunk/modules:~/.bitmunk/modules-dev";
      c["node"][ConfigManager::TMP]["not in changes"] = true;

      // get the changes from defaults to current config
      // serialize this to disk as needed
      DynamicObject changes;
      cm.getChanges(changes);

      // check it's correct
      DynamicObject expect;
      expect["node"]["port"] = 19200;
      expect["node"]["comment"] = "My precious...";
      expect["node"]["userModulePath"] = "~/.bitmunk/modules:~/.bitmunk/modules-dev";
      // NOTE: will not have TMP var
      assertDynoCmp(changes, expect);
   }
   tr.passIfNoException();
#endif

   tr.test("versioning");
   {
      ConfigManager cm;

      cm.getVersions()->clear();
      Config c;
      c[ConfigManager::ID] = "config";
      assert(cm.addConfig(c));
      assertNoException();

      cm.addVersion("1");
      assert(!cm.addConfig(c));
      assertException();
      Exception::clearLast();

      c[ConfigManager::VERSION] = "2";
      cm.removeConfig("config");
      assert(!cm.addConfig(c));
      assertException();
      Exception::clearLast();

      c[ConfigManager::VERSION] = "1";
      assert(cm.addConfig(c));
      assertNoException();

      c[ConfigManager::VERSION] = "2";
      cm.removeConfig("config");
      cm.addVersion("2");
      assert(cm.addConfig(c));
      assertNoException();
   }
   tr.passIfNoException();

   tr.test("empty array & map");
   {
      ConfigManager cm;
      DynamicObject a;
      a[ConfigManager::ID] = "config";
      a[ConfigManager::MERGE][0]->setType(Array);
      a[ConfigManager::MERGE][1]->setType(Map);
      assert(cm.addConfig(a));
      assertNoException();
      DynamicObject expect;
      expect[0]->setType(Array);
      expect[1]->setType(Map);
      assertDynoCmp(cm.getConfig("config"), expect);
   }
   tr.passIfNoException();

   tr.ungroup();
}

class DbConfigTester : public db::test::Tester
{
public:
   DbConfigTester()
   {
      setName("config");
   }

   /**
    * Run automatic unit tests.
    */
   virtual int runAutomaticTests(TestRunner& tr)
   {
      runConfigManagerTest(tr);
      return 0;
   }

   /**
    * Runs interactive unit tests.
    */
   virtual int runInteractiveTests(TestRunner& tr)
   {
      return 0;
   }
};

#ifndef DB_TEST_NO_MAIN
DB_TEST_MAIN(DbConfigTester)
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009 Secure Endpoints Inc.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define OEMRESOURCE

#include "khmapp.h"
#include "AlertContainer.hpp"

namespace nim {

    AlertElement::AlertElement(Alert& a, int index) :
	m_alert(a),
	m_index(index),
	m_monitor(NULL),
        m_err_completed(false),
        m_err_context(NULL),

	el_title(NULL),
	el_message(NULL),
	el_suggestion(NULL),
	el_icon(NULL),
	el_expose(NULL),
	el_progress(NULL)
    {
	AutoLock<Alert> a_lock(&m_alert);

	m_alert->displayed = TRUE;
    }

    AlertElement::~AlertElement()
     {
	 {
	     AutoLock<Alert> a_lock(&m_alert);
	     m_alert->displayed = FALSE;
	 }

	 if (m_monitor)
	     delete m_monitor;
     }

    // alert must be locked
    HICON AlertElement::IconForAlert()
    {
	if ((m_alert->alert_type == KHUI_ALERTTYPE_PROGRESS ||
	     m_alert->alert_type == KHUI_ALERTTYPE_PROGRESSACQ) &&
	    m_alert->severity >= KHERR_INFO &&
	    (m_alert->flags & KHUI_ALERT_FLAG_VALID_ERROR)) {

	    return LoadIconResource(m_err_completed ? IDI_CHECK : IDI_CLOCK);
	} else {
	    return LoadIconResource(
				    (m_alert->severity == KHERR_ERROR)? OIC_HAND :
				    (m_alert->severity == KHERR_WARNING)? OIC_BANG :
				    OIC_NOTE,
				    false, true, NULL
				    );
	}
    }

    DrawState AlertElement::GetDrawState()
    {
	return (DrawState)(0 |
			   (selected ? DrawStateSelected : DrawStateNone) |
			   (highlight ? DrawStateHotTrack : DrawStateNone) |
			   (focus ? DrawStateFocusRect : DrawStateNone));
    }

    void AlertElement::UpdateLayoutPre(Graphics & g, Rect & layout)
    {
	AutoLock<Alert> a_lock(&m_alert);
        bool was_modified = !!(m_alert->flags & KHUI_ALERT_FLAG_MODIFIED);

	if (!el_title) {
	    el_title = PNEW AlertTitleElement();
	    InsertChildAfter(el_title);
	}

        if (m_alert->title && was_modified)
            el_title->SetCaption(std::wstring(m_alert->title));

	if (!el_message) {
	    el_message = PNEW AlertMessageElement();
	    InsertChildAfter(el_message);
	}

        if (m_alert->message && was_modified)
            el_message->SetCaption(std::wstring(m_alert->message));

	if (!el_suggestion) {
	    el_suggestion = PNEW AlertSuggestionElement();
	    InsertChildAfter(el_suggestion);
	}

        if (m_alert->suggestion && was_modified)
            el_suggestion->SetCaption(std::wstring(m_alert->suggestion));

	if (m_alert->flags & KHUI_ALERT_FLAG_VALID_ERROR) {

	    if (!el_progress) {
		el_progress = PNEW ProgressBarElement();
		InsertChildAfter(el_progress);
                UpdateProgress();
	    }

	    if (!el_expose) {
		el_expose = PNEW ExposeControlElement();
		InsertChildAfter(el_expose);
	    }
	}

	if (!el_icon) {
	    el_icon = PNEW IconDisplayElement(g_theme->pt_margin_cx + g_theme->pt_margin_cy,
					     IconForAlert(),
					     true /* Large */);
	    InsertChildAfter(el_icon);
	}

        if (el_buttons.size() == 0 && HasCommands()) {
            AutoLock<Alert> a_lock(&m_alert);

            for (int i = 0; i < m_alert->n_alert_commands; i++) {
                if (m_alert->alert_commands[i] != KHUI_PACTION_CLOSE) {
                    AlertCommandButtonElement * e = PNEW AlertCommandButtonElement();

                    InsertChildAfter(e);
                    el_buttons.push_back(e);

                    e->CreateFromCommand(m_alert->alert_commands[i],
                                         AlertContainer::ControlIdFromIndex(m_index, i));
                }
            }
        }

	extents.Height = 0;
	extents.Width = layout.Width;

	{
	    Size sz_icon = g_theme->sz_margin + g_theme->sz_icon + g_theme->sz_margin;

	    layout.X += sz_icon.Width;
	    layout.Width -= sz_icon.Width;
	}
    }

    void AlertElement::UpdateLayoutPost(Graphics & g, const Rect & bounds)
    {
        int left_indent = g_theme->sz_margin.Width * 2 + g_theme->sz_icon.Width;
        bool has_children = false;

        if (el_expose) {
            for (DisplayElement * e = TQFIRSTCHILD(this); e; e = TQNEXTSIBLING(e)) {
                AlertElement * ae = dynamic_cast<AlertElement *>(e);

                if (ae) {
                    has_children = true;
                    break;
                }
            }
        }

        FlowLayout layout(Rect(Point(0,0),
                               Size(bounds.Width + left_indent, 0)),
                          g_theme->sz_margin);

        layout
            .PushIndent(left_indent - g_theme->sz_margin.Width)
            .LineBreak()
            .Add(el_title)
            .LineBreak()
            .Add(el_message)
            .LineBreak()
            .Add(el_suggestion)
            .LineBreak()
            .Add(el_progress, !m_err_completed)
            .LineBreak()
            .PopIndent()
            .PushIndent(g_theme->sz_margin.Width + g_theme->sz_icon.Width - g_theme->sz_icon_sm.Width)
            .LineBreak()
            .Add(el_expose, FlowLayout::Left, FlowLayout::Fixed, has_children)
            .PopIndent()
            .PushIndent(g_theme->sz_margin.Width + g_theme->sz_icon.Width)
            ;

        for (std::vector<AlertCommandButtonElement *>::iterator i = el_buttons.begin();
             i != el_buttons.end(); ++i) {
            layout.Add(*i);
        }
        layout.LineBreak();

	for (DisplayElement * e = TQFIRSTCHILD(this); e;
	     e = TQNEXTSIBLING(e)) {
	    AlertElement * ca = dynamic_cast<AlertElement *>(e);

	    if (!ca || !ca->visible)
		continue;

            layout.Add(e).LineBreak();
	}

	extents = layout.GetSize();
        extents.Height = max(extents.Height, g_theme->sz_margin.Height * 2 + g_theme->sz_icon.Height);
    }

    void AlertElement::UpdateIcon()
    {
        if (el_icon)
            el_icon->SetIcon(IconForAlert());
    }

    void AlertElement::UpdateProgress()
    {
        khm_ui_4 num, denom;
        int norm_progress;

        if (m_err_context) {
            AutoLock<Alert> a_lock(&m_alert);
            kherr_get_progress_i(m_err_context, &num, &denom);
        } else {
            num = denom = 1;
        }

        if (denom == 0)
            norm_progress = 0;
        else if (num > denom)
            norm_progress = 256;
        else
            norm_progress = (num * 256) / denom;

        if (el_progress)
            el_progress->SetProgress(norm_progress);
        else {
            MarkForExtentUpdate();
            Invalidate();
        }

        if (norm_progress >= 256) {
            m_err_completed = true;
            UpdateIcon();
        }
    }

    void AlertElement::SetMonitor(AlertContextMonitor * m)
    {
        assert (m_monitor == NULL || m == NULL);
	m_monitor = m;
        m_err_context = m_alert->err_context;
        assert(m_err_context != NULL || m == NULL);
    }

    void AlertElement::TryMonitorNewChildContext(kherr_context * c)
    {
	for (DisplayElement * de = TQFIRSTCHILD(this); de;
	     de = TQNEXTSIBLING(de)) {
	    AlertElement * ae = dynamic_cast<AlertElement *>(de);

	    if (ae == NULL)
		continue;

	    {
		AutoLock<Alert> a_lock(&ae->m_alert);

		if (kherr_context_is_equal(c, ae->m_err_context))
		    return;	// Already there
	    }
	}

	// Wasn't there.  We need to create a new alert element and
	// add it to this element

	khui_alert * a = NULL;

	khui_alert_create_empty(&a);
	khui_alert_set_type(a, KHUI_ALERTTYPE_PROGRESSACQ);

	Alert alert(a, true);
	AlertElement * ae = PNEW AlertElement(alert, -1);

	InsertOutlineAfter(ae);

	khui_alert_monitor_progress(a, c,
				    KHUI_AMP_SHOW_EVT_ERR |
				    KHUI_AMP_SHOW_EVT_WARN);

        dynamic_cast<AlertContainer *>(owner)->BeginMonitoringAlert(alert);
    }

    void AlertElement::OnErrCtxEvent(enum kherr_ctx_event e)
    {
        if (m_err_context == NULL)
            return;

	switch (e) {
	case KHERR_CTX_DESCRIBE:
	    {
		AutoLock<Alert> a_lock(&m_alert);
		kherr_event * ev;

		ev = kherr_get_desc_event(m_err_context);
		if (ev) {
		    if (ev->short_desc && ev->long_desc) {
                        khui_alert_set_title(m_alert, ev->long_desc);
                        khui_alert_set_message(m_alert, ev->short_desc);
		    } else if (ev->long_desc) {
                        khui_alert_set_title(m_alert, ev->long_desc);
		    } else if (ev->short_desc) {
                        khui_alert_set_title(m_alert, ev->short_desc);
		    }
		}
                MarkForExtentUpdate();
                Invalidate();
	    }
	    break;

	case KHERR_CTX_END:
	    {
                m_err_completed = true;
                m_err_context = NULL;
		UpdateIcon();
	    }
	    break;

	case KHERR_CTX_EVTCOMMIT:
	case KHERR_CTX_ERROR:
	    {
		AutoLock<Alert> a_lock(&m_alert);
		kherr_event * ev;

		ev = kherr_get_last_event(m_err_context);

		if (((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_ERR) &&
		     ev->severity <= KHERR_ERROR) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_WARN) &&
		     ev->severity <= KHERR_WARNING) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_INFO) &&
		     ev->severity <= KHERR_INFO) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_DEBUG) &&
		     ev->severity <= KHERR_DEBUG_3)) {

		    khui_alert_set_severity(m_alert, ev->severity);

		    if (!(ev->flags & KHERR_RF_STR_RESOLVED))
			kherr_evaluate_event(ev);

		    if (ev->long_desc) {
                        khui_alert_set_message(m_alert, ev->long_desc);
		    } else if (ev->short_desc) {
                        khui_alert_set_message(m_alert, ev->short_desc);
		    }

                    if (ev->suggestion) {
                        khui_alert_set_suggestion(m_alert, ev->suggestion);
                    } else {
                        khui_alert_set_suggestion(m_alert, NULL);
                    }

                    UpdateIcon();
                    MarkForExtentUpdate();
                    Invalidate();
		}
	    }
	    break;

	case KHERR_CTX_NEWCHILD:
	    {
		kherr_context * c;

		{
		    AutoLock<Alert> a_lock(&m_alert);
		    c = kherr_get_first_context(m_err_context);
		}

		for (; c ; c = kherr_get_next_context(c)) {
		    TryMonitorNewChildContext(c);
		}
	    }
	    break;

	case KHERR_CTX_PROGRESS:
	    {
                UpdateProgress();
	    }
	    break;
	}
    }

    void AlertElement::PaintSelf(Graphics &g, const Rect& bounds, const Rect& clip)
    {
	g_theme->DrawAlertBackground(g, bounds, GetDrawState());
    }

    void AlertCommandButtonElement::CreateFromCommand(khm_int32 cmd, UINT ctl_id)
    {
        assert (owner);
        assert (owner->hwnd);

        HWND hwnd_button;
        wchar_t caption[KHUI_MAXCCH_SHORT_DESC] = L"";

        khm_get_action_caption(cmd, caption, sizeof(caption));

        hwnd_button = CreateWindow(L"BUTTON",
                                   caption,
                                   WS_TABSTOP | WS_CHILD | BS_PUSHBUTTON | BS_NOTIFY,
                                   0, 0, 100, 100, // Dummy x,y,width,height
                                   owner->hwnd,
                                   (HMENU)(UINT_PTR) ctl_id,
                                   khm_hInstance,
                                   NULL);
        SendMessage(hwnd_button, WM_SETFONT, (WPARAM) g_theme->hf_normal, FALSE);
        SetWindow(hwnd_button);
    }

    void AlertCommandButtonElement::UpdateLayoutPre(Graphics& g, Rect& layout)
    {
        HWND hwnd_button;

        hwnd_button = GetWindow();

        if (hwnd_button) {
            wchar_t caption[KHUI_MAXCCH_SHORT_DESC] = L"";
            HFONT hf;
            Font * font;

            GetWindowText(hwnd_button, caption, ARRAYLENGTH(caption));
            hf = (HFONT) SendMessage(hwnd_button, WM_GETFONT, 0, 0);
            if (hf == NULL)
                hf = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
            {
                HDC hdc = g.GetHDC();
                font = new Font(hdc, hf);
                g.ReleaseHDC(hdc);
            }

            StringFormat fmt(StringFormatFlagsNoWrap);
            RectF brect;

            g.MeasureString(caption, -1, font, PointF(0.0, 0.0), &fmt, &brect);

            int bwidth = (int) brect.Width + g_theme->sz_margin.Width * 2;
            int bheight = (int) brect.Height + g_theme->sz_margin.Height * 2;

            SetWindowPos(hwnd_button, NULL, 0, 0,
                         bwidth, bheight, SWP_SIZEONLY);

            delete font;
        }
    }
}
<commit_msg>Use the correct event object when handling an error context notification<commit_after>/*
 * Copyright (c) 2009 Secure Endpoints Inc.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define OEMRESOURCE

#include "khmapp.h"
#include "AlertContainer.hpp"

namespace nim {

    AlertElement::AlertElement(Alert& a, int index) :
	m_alert(a),
	m_index(index),
	m_monitor(NULL),
        m_err_completed(false),
        m_err_context(NULL),

	el_title(NULL),
	el_message(NULL),
	el_suggestion(NULL),
	el_icon(NULL),
	el_expose(NULL),
	el_progress(NULL)
    {
	AutoLock<Alert> a_lock(&m_alert);

	m_alert->displayed = TRUE;
    }

    AlertElement::~AlertElement()
     {
	 {
	     AutoLock<Alert> a_lock(&m_alert);
	     m_alert->displayed = FALSE;
	 }

	 if (m_monitor)
	     delete m_monitor;
     }

    // alert must be locked
    HICON AlertElement::IconForAlert()
    {
	if ((m_alert->alert_type == KHUI_ALERTTYPE_PROGRESS ||
	     m_alert->alert_type == KHUI_ALERTTYPE_PROGRESSACQ) &&
	    m_alert->severity >= KHERR_INFO &&
	    (m_alert->flags & KHUI_ALERT_FLAG_VALID_ERROR)) {

	    return LoadIconResource(m_err_completed ? IDI_CHECK : IDI_CLOCK);
	} else {
	    return LoadIconResource(
				    (m_alert->severity == KHERR_ERROR)? OIC_HAND :
				    (m_alert->severity == KHERR_WARNING)? OIC_BANG :
				    OIC_NOTE,
				    false, true, NULL
				    );
	}
    }

    DrawState AlertElement::GetDrawState()
    {
	return (DrawState)(0 |
			   (selected ? DrawStateSelected : DrawStateNone) |
			   (highlight ? DrawStateHotTrack : DrawStateNone) |
			   (focus ? DrawStateFocusRect : DrawStateNone));
    }

    void AlertElement::UpdateLayoutPre(Graphics & g, Rect & layout)
    {
	AutoLock<Alert> a_lock(&m_alert);
        bool was_modified = !!(m_alert->flags & KHUI_ALERT_FLAG_MODIFIED);

	if (!el_title) {
	    el_title = PNEW AlertTitleElement();
	    InsertChildAfter(el_title);
	}

        if (m_alert->title && was_modified)
            el_title->SetCaption(std::wstring(m_alert->title));

	if (!el_message) {
	    el_message = PNEW AlertMessageElement();
	    InsertChildAfter(el_message);
	}

        if (m_alert->message && was_modified)
            el_message->SetCaption(std::wstring(m_alert->message));

	if (!el_suggestion) {
	    el_suggestion = PNEW AlertSuggestionElement();
	    InsertChildAfter(el_suggestion);
	}

        if (m_alert->suggestion && was_modified)
            el_suggestion->SetCaption(std::wstring(m_alert->suggestion));

	if (m_alert->flags & KHUI_ALERT_FLAG_VALID_ERROR) {

	    if (!el_progress) {
		el_progress = PNEW ProgressBarElement();
		InsertChildAfter(el_progress);
                UpdateProgress();
	    }

	    if (!el_expose) {
		el_expose = PNEW ExposeControlElement();
		InsertChildAfter(el_expose);
	    }
	}

	if (!el_icon) {
	    el_icon = PNEW IconDisplayElement(g_theme->pt_margin_cx + g_theme->pt_margin_cy,
					     IconForAlert(),
					     true /* Large */);
	    InsertChildAfter(el_icon);
	}

        if (el_buttons.size() == 0 && HasCommands()) {
            AutoLock<Alert> a_lock(&m_alert);

            for (int i = 0; i < m_alert->n_alert_commands; i++) {
                if (m_alert->alert_commands[i] != KHUI_PACTION_CLOSE) {
                    AlertCommandButtonElement * e = PNEW AlertCommandButtonElement();

                    InsertChildAfter(e);
                    el_buttons.push_back(e);

                    e->CreateFromCommand(m_alert->alert_commands[i],
                                         AlertContainer::ControlIdFromIndex(m_index, i));
                }
            }
        }

	extents.Height = 0;
	extents.Width = layout.Width;

	{
	    Size sz_icon = g_theme->sz_margin + g_theme->sz_icon + g_theme->sz_margin;

	    layout.X += sz_icon.Width;
	    layout.Width -= sz_icon.Width;
	}
    }

    void AlertElement::UpdateLayoutPost(Graphics & g, const Rect & bounds)
    {
        int left_indent = g_theme->sz_margin.Width * 2 + g_theme->sz_icon.Width;
        bool has_children = false;

        if (el_expose) {
            for (DisplayElement * e = TQFIRSTCHILD(this); e; e = TQNEXTSIBLING(e)) {
                AlertElement * ae = dynamic_cast<AlertElement *>(e);

                if (ae) {
                    has_children = true;
                    break;
                }
            }
        }

        FlowLayout layout(Rect(Point(0,0),
                               Size(bounds.Width + left_indent, 0)),
                          g_theme->sz_margin);

        layout
            .PushIndent(left_indent - g_theme->sz_margin.Width)
            .LineBreak()
            .Add(el_title)
            .LineBreak()
            .Add(el_message)
            .LineBreak()
            .Add(el_suggestion)
            .LineBreak()
            .Add(el_progress, !m_err_completed)
            .LineBreak()
            .PopIndent()
            .PushIndent(g_theme->sz_margin.Width + g_theme->sz_icon.Width - g_theme->sz_icon_sm.Width)
            .LineBreak()
            .Add(el_expose, FlowLayout::Left, FlowLayout::Fixed, has_children)
            .PopIndent()
            .PushIndent(g_theme->sz_margin.Width + g_theme->sz_icon.Width)
            ;

        for (std::vector<AlertCommandButtonElement *>::iterator i = el_buttons.begin();
             i != el_buttons.end(); ++i) {
            layout.Add(*i);
        }
        layout.LineBreak();

	for (DisplayElement * e = TQFIRSTCHILD(this); e;
	     e = TQNEXTSIBLING(e)) {
	    AlertElement * ca = dynamic_cast<AlertElement *>(e);

	    if (!ca || !ca->visible)
		continue;

            layout.Add(e).LineBreak();
	}

	extents = layout.GetSize();
        extents.Height = max(extents.Height, g_theme->sz_margin.Height * 2 + g_theme->sz_icon.Height);
    }

    void AlertElement::UpdateIcon()
    {
        if (el_icon)
            el_icon->SetIcon(IconForAlert());
    }

    void AlertElement::UpdateProgress()
    {
        khm_ui_4 num, denom;
        int norm_progress;

        if (m_err_context) {
            AutoLock<Alert> a_lock(&m_alert);
            kherr_get_progress_i(m_err_context, &num, &denom);
        } else {
            num = denom = 1;
        }

        if (denom == 0)
            norm_progress = 0;
        else if (num > denom)
            norm_progress = 256;
        else
            norm_progress = (num * 256) / denom;

        if (el_progress)
            el_progress->SetProgress(norm_progress);
        else {
            MarkForExtentUpdate();
            Invalidate();
        }

        if (norm_progress >= 256) {
            m_err_completed = true;
            UpdateIcon();
        }
    }

    void AlertElement::SetMonitor(AlertContextMonitor * m)
    {
        assert (m_monitor == NULL || m == NULL);
	m_monitor = m;
        m_err_context = m_alert->err_context;
        assert(m_err_context != NULL || m == NULL);
    }

    void AlertElement::TryMonitorNewChildContext(kherr_context * c)
    {
	for (DisplayElement * de = TQFIRSTCHILD(this); de;
	     de = TQNEXTSIBLING(de)) {
	    AlertElement * ae = dynamic_cast<AlertElement *>(de);

	    if (ae == NULL)
		continue;

	    {
		AutoLock<Alert> a_lock(&ae->m_alert);

		if (kherr_context_is_equal(c, ae->m_err_context))
		    return;	// Already there
	    }
	}

	// Wasn't there.  We need to create a new alert element and
	// add it to this element

	khui_alert * a = NULL;

	khui_alert_create_empty(&a);
	khui_alert_set_type(a, KHUI_ALERTTYPE_PROGRESSACQ);

	Alert alert(a, true);
	AlertElement * ae = PNEW AlertElement(alert, -1);

	InsertOutlineAfter(ae);

	khui_alert_monitor_progress(a, c,
				    KHUI_AMP_SHOW_EVT_ERR |
				    KHUI_AMP_SHOW_EVT_WARN);

        dynamic_cast<AlertContainer *>(owner)->BeginMonitoringAlert(alert);
    }

    void AlertElement::OnErrCtxEvent(enum kherr_ctx_event e)
    {
        if (m_err_context == NULL)
            return;

	switch (e) {
	case KHERR_CTX_DESCRIBE:
	    {
		AutoLock<Alert> a_lock(&m_alert);
		kherr_event * ev;

		ev = kherr_get_desc_event(m_err_context);
		if (ev) {
		    if (ev->short_desc && ev->long_desc) {
                        khui_alert_set_title(m_alert, ev->long_desc);
                        khui_alert_set_message(m_alert, ev->short_desc);
		    } else if (ev->long_desc) {
                        khui_alert_set_title(m_alert, ev->long_desc);
		    } else if (ev->short_desc) {
                        khui_alert_set_title(m_alert, ev->short_desc);
		    }
		}
                MarkForExtentUpdate();
                Invalidate();
	    }
	    break;

	case KHERR_CTX_END:
	    {
                m_err_completed = true;
                m_err_context = NULL;
		UpdateIcon();
	    }
	    break;

	case KHERR_CTX_EVTCOMMIT:
	case KHERR_CTX_ERROR:
	    {
		AutoLock<Alert> a_lock(&m_alert);
		kherr_event * ev;

                if (e == KHERR_CTX_EVTCOMMIT) {
                    ev = kherr_get_last_event(m_err_context);
                    if (ev->severity > m_alert->severity)
                        break;
                } else {
                    ev = kherr_get_err_event(m_err_context);
                }

                if (ev == NULL)
                    break;

		if (((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_ERR) &&
		     ev->severity <= KHERR_ERROR) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_WARN) &&
		     ev->severity <= KHERR_WARNING) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_INFO) &&
		     ev->severity <= KHERR_INFO) ||

		    ((m_alert->monitor_flags & KHUI_AMP_SHOW_EVT_DEBUG) &&
		     ev->severity <= KHERR_DEBUG_3)) {

		    khui_alert_set_severity(m_alert, ev->severity);

		    if (!(ev->flags & KHERR_RF_STR_RESOLVED))
			kherr_evaluate_event(ev);

		    if (ev->long_desc) {
                        khui_alert_set_message(m_alert, ev->long_desc);
		    } else if (ev->short_desc) {
                        khui_alert_set_message(m_alert, ev->short_desc);
		    }

                    if (ev->suggestion) {
                        khui_alert_set_suggestion(m_alert, ev->suggestion);
                    } else {
                        khui_alert_set_suggestion(m_alert, NULL);
                    }

                    UpdateIcon();
                    MarkForExtentUpdate();
                    Invalidate();
		}
	    }
	    break;

	case KHERR_CTX_NEWCHILD:
	    {
		kherr_context * c;

		{
		    AutoLock<Alert> a_lock(&m_alert);
		    c = kherr_get_first_context(m_err_context);
		}

		for (; c ; c = kherr_get_next_context(c)) {
		    TryMonitorNewChildContext(c);
		}
	    }
	    break;

	case KHERR_CTX_PROGRESS:
	    {
                UpdateProgress();
	    }
	    break;
	}
    }

    void AlertElement::PaintSelf(Graphics &g, const Rect& bounds, const Rect& clip)
    {
	g_theme->DrawAlertBackground(g, bounds, GetDrawState());
    }

    void AlertCommandButtonElement::CreateFromCommand(khm_int32 cmd, UINT ctl_id)
    {
        assert (owner);
        assert (owner->hwnd);

        HWND hwnd_button;
        wchar_t caption[KHUI_MAXCCH_SHORT_DESC] = L"";

        khm_get_action_caption(cmd, caption, sizeof(caption));

        hwnd_button = CreateWindow(L"BUTTON",
                                   caption,
                                   WS_TABSTOP | WS_CHILD | BS_PUSHBUTTON | BS_NOTIFY,
                                   0, 0, 100, 100, // Dummy x,y,width,height
                                   owner->hwnd,
                                   (HMENU)(UINT_PTR) ctl_id,
                                   khm_hInstance,
                                   NULL);
        SendMessage(hwnd_button, WM_SETFONT, (WPARAM) g_theme->hf_normal, FALSE);
        SetWindow(hwnd_button);
    }

    void AlertCommandButtonElement::UpdateLayoutPre(Graphics& g, Rect& layout)
    {
        HWND hwnd_button;

        hwnd_button = GetWindow();

        if (hwnd_button) {
            wchar_t caption[KHUI_MAXCCH_SHORT_DESC] = L"";
            HFONT hf;
            Font * font;

            GetWindowText(hwnd_button, caption, ARRAYLENGTH(caption));
            hf = (HFONT) SendMessage(hwnd_button, WM_GETFONT, 0, 0);
            if (hf == NULL)
                hf = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
            {
                HDC hdc = g.GetHDC();
                font = new Font(hdc, hf);
                g.ReleaseHDC(hdc);
            }

            StringFormat fmt(StringFormatFlagsNoWrap);
            RectF brect;

            g.MeasureString(caption, -1, font, PointF(0.0, 0.0), &fmt, &brect);

            int bwidth = (int) brect.Width + g_theme->sz_margin.Width * 2;
            int bheight = (int) brect.Height + g_theme->sz_margin.Height * 2;

            SetWindowPos(hwnd_button, NULL, 0, 0,
                         bwidth, bheight, SWP_SIZEONLY);

            delete font;
        }
    }
}
<|endoftext|>


<commit_before>#include "tinfra/io/stream.h"
#include "tinfra/io/socket.h"
#include "tinfra/thread.h"
#include "tinfra/string.h"
#include "tinfra/server.h"
#include <ostream>
#include <istream>
#include <iostream>
#include <sstream>
#include <string>

#include <unittest++/UnitTest++.h>
#include "tinfra/test.h"

class Client: public tinfra::Runnable {
    std::auto_ptr<tinfra::io::stream> client;
    tinfra::net::Server& server;
public:
    Client(std::auto_ptr<tinfra::io::stream> _client, tinfra::net::Server& _server)
        : client(_client), server(_server) {}

    virtual void run()
    {

        bool connected = true;
        std::string response;
        //response = "hello!";
        //client->write(response.c_str(), response.size());
        //client->write("\r\n",2);
        while( connected ) {
            {
                tinfra::io::zstreambuf buf(client.get());
                std::istream in(&buf);
                std::string cmd;
                std::getline(in, cmd);
                tinfra::strip_inplace(cmd);
                //std::cerr << "S<" << cmd << std::endl;
                if( cmd == "stop") {
                    server.stop();
                    connected = false;
                    response = "quitting";
                } else if( cmd == "close" ) {
                    connected = false;
                    response = "bye";
                } else {
                    response = cmd;
                }
            }
            {
                //std::cerr << "S>" << response << std::endl;
                client->write(response.c_str(), response.size());
                client->write("\r\n",2);
            }
        }
        delete this;
    }
};

class TestServer: public tinfra::net::Server, public tinfra::Runnable {
public:
    virtual void onAccept(std::auto_ptr<tinfra::io::stream> client, std::string const&) {
        Runnable* worker = new Client(client, *this);
        //tinfra::Thread::start_detached(*worker);
        worker->run();
    }

    virtual void run()
    {
        tinfra::net::Server::run();
    }
};

std::string invoke(std::istream& in, std::ostream& out, std::string const& msg)
{
    out << msg << std::endl;
    out.flush();
    //std::cerr << "C>'" << tinfra::escape_c(msg) << "'" << std::endl;
    std::string tmp;
    std::getline(in, tmp);
    tinfra::strip_inplace(tmp);
    //std::cerr << "C<'" << tinfra::escape_c(tmp) << "'" << std::endl;
    return tmp;
}
SUITE(tinfra_server)
{
    TEST(test_server_generic)
    {
        TestServer server;
        server.bind("localhost", 10900);
        tinfra::ThreadSet ts;
        tinfra::Thread server_thread = ts.start(server);
        {
            std::auto_ptr<tinfra::io::stream> client(tinfra::io::socket::open_client_socket("localhost",10900));

            tinfra::io::zstreambuf ibuf(client.get());
            tinfra::io::zstreambuf obuf(client.get());

            std::istream in(&ibuf);
            std::ostream out(&obuf);

            CHECK_EQUAL( "zbyszek", invoke(in,out, "zbyszek"));
            CHECK_EQUAL( "A", invoke(in,out, "A"));
            CHECK_EQUAL( "", invoke(in,out, ""));
            CHECK_EQUAL( "quitting", invoke(in,out, "stop"));
        }
        server.stop();
    }

    // check if Server::stop can abort blocking accept call
    TEST(test_server_stop)
    {
        TestServer server;
        server.bind("localhost", 10901);
        tinfra::ThreadSet ts;
        ts.start(server);

        server.stop();
    }
}
<commit_msg>test_server: described failing test case as TODO with explanation<commit_after>#include "tinfra/io/stream.h"
#include "tinfra/io/socket.h"
#include "tinfra/thread.h"
#include "tinfra/string.h"
#include "tinfra/server.h"
#include <ostream>
#include <istream>
#include <iostream>
#include <sstream>
#include <string>

#include <unittest++/UnitTest++.h>
#include "tinfra/test.h"

class Client: public tinfra::Runnable {
    std::auto_ptr<tinfra::io::stream> client;
    tinfra::net::Server& server;
public:
    Client(std::auto_ptr<tinfra::io::stream> _client, tinfra::net::Server& _server)
        : client(_client), server(_server) {}

    virtual void run()
    {

        bool connected = true;
        std::string response;
        //response = "hello!";
        //client->write(response.c_str(), response.size());
        //client->write("\r\n",2);
        while( connected ) {
            {
                tinfra::io::zstreambuf buf(client.get());
                std::istream in(&buf);
                std::string cmd;
                std::getline(in, cmd);
                tinfra::strip_inplace(cmd);
                //std::cerr << "S<" << cmd << std::endl;
                if( cmd == "stop") {
                    server.stop();
                    connected = false;
                    response = "quitting";
                } else if( cmd == "close" ) {
                    connected = false;
                    response = "bye";
                } else {
                    response = cmd;
                }
            }
            {
                //std::cerr << "S>" << response << std::endl;
                client->write(response.c_str(), response.size());
                client->write("\r\n",2);
            }
        }
        delete this;
    }
};

class TestServer: public tinfra::net::Server, public tinfra::Runnable {
public:
    virtual void onAccept(std::auto_ptr<tinfra::io::stream> client, std::string const&) {
        Runnable* worker = new Client(client, *this);
        //tinfra::Thread::start_detached(*worker);
        worker->run();
    }

    virtual void run()
    {
        tinfra::net::Server::run();
    }
};

std::string invoke(std::istream& in, std::ostream& out, std::string const& msg)
{
    out << msg << std::endl;
    out.flush();
    //std::cerr << "C>'" << tinfra::escape_c(msg) << "'" << std::endl;
    std::string tmp;
    std::getline(in, tmp);
    tinfra::strip_inplace(tmp);
    //std::cerr << "C<'" << tinfra::escape_c(tmp) << "'" << std::endl;
    return tmp;
}
SUITE(tinfra_server)
{
    TEST(test_server_generic)
    {
        TestServer server;
        server.bind("localhost", 10900);
        tinfra::ThreadSet ts;
        tinfra::Thread server_thread = ts.start(server);
        {
            std::auto_ptr<tinfra::io::stream> client(tinfra::io::socket::open_client_socket("localhost",10900));

            tinfra::io::zstreambuf ibuf(client.get());
            tinfra::io::zstreambuf obuf(client.get());

            std::istream in(&ibuf);
            std::ostream out(&obuf);

            // TODO: this test fails with "zyszek" sometimes
	    //       because zstreambuf is broken
	    //       in following read sequence:
	    //  sendto(4, "zbyszek", 7, 0, NULL, 0)     = 7
	    //  sendto(4, "\n", 1, 0, NULL, 0)          = 1
	    //  recvfrom(4, "z", 1, 0, NULL, NULL)      = 1
	    //  recvfrom(4, "byszek", 32768, 0, NULL, NULL) = 6
	    //  recvfrom(4, "\r\n", 32768, 0, NULL, NULL) = 2
	    //
	    // and thus std::getline( returns "zyszek\r\n")

            CHECK_EQUAL( "zbyszek", invoke(in,out, "zbyszek"));

            CHECK_EQUAL( "A", invoke(in,out, "A"));
            CHECK_EQUAL( "", invoke(in,out, ""));
            CHECK_EQUAL( "quitting", invoke(in,out, "stop"));
        }
        server.stop();
    }

    // check if Server::stop can abort blocking accept call
    TEST(test_server_stop)
    {
        TestServer server;
        server.bind("localhost", 10901);
        tinfra::ThreadSet ts;
        ts.start(server);

        server.stop();
    }
}
<|endoftext|>


<commit_before>#include "UnitTest.h"
#include "../Source/Utility/Buffer.h"

using namespace vl;
using namespace vl::database;

extern WString GetTempFolder();
#define TEMP_DIR GetTempFolder()+
#define KB *1024
#define MB *1024*1024

TEST_CASE(Utility_Buffer_AddRemoveSource)
{
	BufferManager bm(64 KB, 1 MB);
	auto a = bm.LoadMemorySource();
	auto b = bm.LoadFileSource(TEMP_DIR L"db.bin", true);
	TEST_ASSERT(bm.GetSourceFileName(a) == L"");
	TEST_ASSERT(bm.GetSourceFileName(b) == TEMP_DIR L"db.bin");

	bm.UnloadSource(a);
	bm.UnloadSource(b);
	TEST_ASSERT(bm.GetSourceFileName(a) == L"");
	TEST_ASSERT(bm.GetSourceFileName(b) == L"");

	a = bm.LoadMemorySource();
	b = bm.LoadFileSource(TEMP_DIR L"db.bin", true);
	TEST_ASSERT(bm.GetSourceFileName(a) == L"");
	TEST_ASSERT(bm.GetSourceFileName(b) == TEMP_DIR L"db.bin");
}
<commit_msg>Macro for in-memory/file buffer source unit test<commit_after>#include "UnitTest.h"
#include "../Source/Utility/Buffer.h"

using namespace vl;
using namespace vl::database;

extern WString GetTempFolder();
#define TEMP_DIR GetTempFolder()+
#define KB *1024
#define MB *1024*1024

TEST_CASE(Utility_Buffer_AddRemoveSource)
{
	BufferManager bm(64 KB, 1 MB);
	auto a = bm.LoadMemorySource();
	auto b = bm.LoadFileSource(TEMP_DIR L"db.bin", true);
	TEST_ASSERT(bm.GetSourceFileName(a) == L"");
	TEST_ASSERT(bm.GetSourceFileName(b) == TEMP_DIR L"db.bin");

	bm.UnloadSource(a);
	bm.UnloadSource(b);
	TEST_ASSERT(bm.GetSourceFileName(a) == L"");
	TEST_ASSERT(bm.GetSourceFileName(b) == L"");

	a = bm.LoadMemorySource();
	b = bm.LoadFileSource(TEMP_DIR L"db.bin", true);
	TEST_ASSERT(bm.GetSourceFileName(a) == L"");
	TEST_ASSERT(bm.GetSourceFileName(b) == TEMP_DIR L"db.bin");
}

#define TEST_CASE_SOURCE(NAME)														\
extern void TestCase_Utility_Buffer_##NAME(BufferManager& bm, BufferSource source);	\
TEST_CASE(Utility_Buffer_InMemory_##NAME)											\
{																					\
	BufferManager bm(64 KB, 1 MB);													\
	auto source = bm.LoadMemorySource();											\
	TestCase_Utility_Buffer_##NAME(bm, source);										\
}																					\
TEST_CASE(Utility_Buffer_File_##NAME)												\
{																					\
	BufferManager bm(64 KB, 1 MB);													\
	auto source = bm.LoadFileSource(TEMP_DIR L"db.bin", true);						\
	TestCase_Utility_Buffer_##NAME(bm, source);										\
}																					\
void TestCase_Utility_Buffer_##NAME(BufferManager& bm, BufferSource source)			\

TEST_CASE_SOURCE(AllocateFreePage)
{
}

TEST_CASE_SOURCE(LockUnlockPage)
{
}
<|endoftext|>