Merge branch 'jerry-sandbox'

This commit is contained in:
XinyuHou 2015-04-15 13:33:39 +01:00
commit 2752d24dc4
18 changed files with 297 additions and 88 deletions

View File

@ -27,6 +27,9 @@
#include <algorithm> #include <algorithm>
#include <stdio.h> #include <stdio.h>
#include <cstdarg> #include <cstdarg>
#include <sstream>
#include <iomanip>
#include <algorithm>
namespace synergy { namespace synergy {
namespace string { namespace string {
@ -180,6 +183,30 @@ removeFileExt(String filename)
return filename.substr(0, dot); return filename.substr(0, dot);
} }
void
toHex(String& subject, int width, const char fill)
{
std::stringstream ss;
ss << std::hex;
for (unsigned int i = 0; i < subject.length(); i++) {
ss << std::setw(width) << std::setfill(fill) << (int)(unsigned char)subject[i];
}
subject = ss.str();
}
void
uppercase(String& subject)
{
std::transform(subject.begin(), subject.end(), subject.begin(), ::toupper);
}
void
removeChar(String& subject, const char c)
{
subject.erase(std::remove(subject.begin(), subject.end(), c), subject.end());
}
// //
// CaselessCmp // CaselessCmp
// //

View File

@ -70,6 +70,25 @@ Finds the last dot and remove all characters from the dot to the end
*/ */
String removeFileExt(String filename); String removeFileExt(String filename);
//! Convert into hexdecimal
/*!
Convert each character in \c subject into hexdecimal form with \c width
*/
void toHex(String& subject, int width, const char fill = '0');
//! Convert to all uppercase
/*!
Convert each character in \c subject to uppercase
*/
void uppercase(String& subject);
//! Remove all specific char in suject
/*!
Remove all specific \c char in \c suject
*/
void removeChar(String& subject, const char c);
//! Case-insensitive comparisons //! Case-insensitive comparisons
/*! /*!
This class provides case-insensitve comparison functions. This class provides case-insensitve comparison functions.

View File

@ -60,8 +60,7 @@ Client::Client(
const String& name, const NetworkAddress& address, const String& name, const NetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
synergy::Screen* screen, synergy::Screen* screen,
bool enableDragDrop, ClientArgs args) :
bool enableCrypto) :
m_mock(false), m_mock(false),
m_name(name), m_name(name),
m_serverAddress(address), m_serverAddress(address),
@ -77,9 +76,9 @@ Client::Client(
m_events(events), m_events(events),
m_sendFileThread(NULL), m_sendFileThread(NULL),
m_writeToDropDirThread(NULL), m_writeToDropDirThread(NULL),
m_enableDragDrop(enableDragDrop),
m_socket(NULL), m_socket(NULL),
m_useSecureNetwork(false) m_useSecureNetwork(false),
m_args(args)
{ {
assert(m_socketFactory != NULL); assert(m_socketFactory != NULL);
assert(m_screen != NULL); assert(m_screen != NULL);
@ -94,7 +93,7 @@ Client::Client(
new TMethodEventJob<Client>(this, new TMethodEventJob<Client>(this,
&Client::handleResume)); &Client::handleResume));
if (m_enableDragDrop) { if (m_args.m_enableDragDrop) {
m_events->adoptHandler(m_events->forIScreen().fileChunkSending(), m_events->adoptHandler(m_events->forIScreen().fileChunkSending(),
this, this,
new TMethodEventJob<Client>(this, new TMethodEventJob<Client>(this,
@ -105,7 +104,7 @@ Client::Client(
&Client::handleFileRecieveCompleted)); &Client::handleFileRecieveCompleted));
} }
if (enableCrypto) { if (m_args.m_enableCrypto) {
m_useSecureNetwork = ARCH->plugin().exists(s_networkSecurity); m_useSecureNetwork = ARCH->plugin().exists(s_networkSecurity);
if (m_useSecureNetwork == false) { if (m_useSecureNetwork == false) {
LOG((CLOG_NOTE "crypto disabled because of ns plugin not available")); LOG((CLOG_NOTE "crypto disabled because of ns plugin not available"));
@ -162,6 +161,7 @@ Client::connect()
// create the socket // create the socket
IDataSocket* socket = m_socketFactory->create(m_useSecureNetwork); IDataSocket* socket = m_socketFactory->create(m_useSecureNetwork);
m_socket = dynamic_cast<TCPSocket*>(socket); m_socket = dynamic_cast<TCPSocket*>(socket);
m_socket->setFingerprintFilename(m_args.m_certFingerprintFilename);
// filter socket messages, including a packetizing filter // filter socket messages, including a packetizing filter
m_stream = socket; m_stream = socket;
@ -780,7 +780,8 @@ Client::fileChunkReceived(String data)
void void
Client::dragInfoReceived(UInt32 fileNum, String data) Client::dragInfoReceived(UInt32 fileNum, String data)
{ {
if (!m_enableDragDrop) { // TODO: fix duplicate function from CServer
if (!m_args.m_enableDragDrop) {
LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info.")); LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info."));
return; return;
} }

View File

@ -23,6 +23,7 @@
#include "synergy/IClipboard.h" #include "synergy/IClipboard.h"
#include "synergy/DragInformation.h" #include "synergy/DragInformation.h"
#include "synergy/INode.h" #include "synergy/INode.h"
#include "synergy/ClientArgs.h"
#include "net/NetworkAddress.h" #include "net/NetworkAddress.h"
#include "base/EventTypes.h" #include "base/EventTypes.h"
@ -59,8 +60,7 @@ public:
const String& name, const NetworkAddress& address, const String& name, const NetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
synergy::Screen* screen, synergy::Screen* screen,
bool enableDragDrop, ClientArgs args);
bool enableCrypto);
~Client(); ~Client();
#ifdef TEST_ENV #ifdef TEST_ENV
@ -224,7 +224,7 @@ private:
String m_dragFileExt; String m_dragFileExt;
Thread* m_sendFileThread; Thread* m_sendFileThread;
Thread* m_writeToDropDirThread; Thread* m_writeToDropDirThread;
bool m_enableDragDrop;
TCPSocket* m_socket; TCPSocket* m_socket;
bool m_useSecureNetwork; bool m_useSecureNetwork;
ClientArgs m_args;
}; };

View File

@ -18,7 +18,6 @@
#include "mt/Thread.h" #include "mt/Thread.h"
#include "net/XSocket.h"
#include "mt/XMT.h" #include "mt/XMT.h"
#include "mt/XThread.h" #include "mt/XThread.h"
#include "arch/Arch.h" #include "arch/Arch.h"
@ -158,11 +157,6 @@ Thread::threadFunc(void* vjob)
job->run(); job->run();
LOG((CLOG_DEBUG1 "thread 0x%08x exit", id)); LOG((CLOG_DEBUG1 "thread 0x%08x exit", id));
} }
catch (XSocket& e) {
// client called cancel()
LOG((CLOG_DEBUG "%s", e.what()));
}
catch (XThreadCancel&) { catch (XThreadCancel&) {
// client called cancel() // client called cancel()
LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id)); LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id));

View File

@ -112,27 +112,35 @@ TCPListenSocket::accept()
try { try {
socket = new TCPSocket(m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL)); socket = new TCPSocket(m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL));
if (socket != NULL) { if (socket != NULL) {
m_socketMultiplexer->addSocket(this, setListeningJob();
new TSocketMultiplexerMethodJob<TCPListenSocket>(
this, &TCPListenSocket::serviceListening,
m_socket, true, false));
} }
return socket; return socket;
} }
catch (XArchNetwork&) { catch (XArchNetwork&) {
if (socket != NULL) { if (socket != NULL) {
delete socket; delete socket;
setListeningJob();
} }
return NULL; return NULL;
} }
catch (std::exception &ex) { catch (std::exception &ex) {
if (socket != NULL) { if (socket != NULL) {
delete socket; delete socket;
setListeningJob();
} }
throw ex; throw ex;
} }
} }
void
TCPListenSocket::setListeningJob()
{
m_socketMultiplexer->addSocket(this,
new TSocketMultiplexerMethodJob<TCPListenSocket>(
this, &TCPListenSocket::serviceListening,
m_socket, true, false));
}
ISocketMultiplexerJob* ISocketMultiplexerJob*
TCPListenSocket::serviceListening(ISocketMultiplexerJob* job, TCPListenSocket::serviceListening(ISocketMultiplexerJob* job,
bool read, bool, bool error) bool read, bool, bool error)

View File

@ -45,6 +45,9 @@ public:
accept(); accept();
virtual void deleteSocket(void*) { } virtual void deleteSocket(void*) { }
protected:
void setListeningJob();
public: public:
ISocketMultiplexerJob* ISocketMultiplexerJob*
serviceListening(ISocketMultiplexerJob*, serviceListening(ISocketMultiplexerJob*,

View File

@ -59,6 +59,7 @@ public:
virtual void secureConnect() {} virtual void secureConnect() {}
virtual void secureAccept() {} virtual void secureAccept() {}
virtual void setFingerprintFilename(String& f) {}
protected: protected:
ArchSocket getSocket() { return m_socket; } ArchSocket getSocket() { return m_socket; }

View File

@ -54,10 +54,13 @@ SecureListenSocket::accept()
m_events, m_events,
m_socketMultiplexer, m_socketMultiplexer,
ARCH->acceptSocket(m_socket, NULL)); ARCH->acceptSocket(m_socket, NULL));
socket->initSsl(true);
m_secureSocketSet.insert(socket); m_secureSocketSet.insert(socket);
socket->initSsl(true); if (socket != NULL) {
setListeningJob();
}
// TODO: customized certificate path // TODO: customized certificate path
String certificateFilename = ARCH->getProfileDirectory(); String certificateFilename = ARCH->getProfileDirectory();
#if SYSAPI_WIN32 #if SYSAPI_WIN32
@ -67,26 +70,27 @@ SecureListenSocket::accept()
#endif #endif
certificateFilename.append(s_certificateFilename); certificateFilename.append(s_certificateFilename);
socket->loadCertificates(certificateFilename.c_str()); bool loaded = socket->loadCertificates(certificateFilename);
if (!loaded) {
delete socket;
return NULL;
}
socket->secureAccept(); socket->secureAccept();
if (socket != NULL) {
m_socketMultiplexer->addSocket(this,
new TSocketMultiplexerMethodJob<TCPListenSocket>(
this, &TCPListenSocket::serviceListening,
m_socket, true, false));
}
return dynamic_cast<IDataSocket*>(socket); return dynamic_cast<IDataSocket*>(socket);
} }
catch (XArchNetwork&) { catch (XArchNetwork&) {
if (socket != NULL) { if (socket != NULL) {
delete socket; delete socket;
setListeningJob();
} }
return NULL; return NULL;
} }
catch (std::exception &ex) { catch (std::exception &ex) {
if (socket != NULL) { if (socket != NULL) {
delete socket; delete socket;
setListeningJob();
} }
throw ex; throw ex;
} }

View File

@ -28,6 +28,7 @@
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
#include <fstream>
// //
// SecureSocket // SecureSocket
@ -44,7 +45,8 @@ SecureSocket::SecureSocket(
IEventQueue* events, IEventQueue* events,
SocketMultiplexer* socketMultiplexer) : SocketMultiplexer* socketMultiplexer) :
TCPSocket(events, socketMultiplexer), TCPSocket(events, socketMultiplexer),
m_secureReady(false) m_secureReady(false),
m_certFingerprintFilename()
{ {
} }
@ -149,24 +151,46 @@ SecureSocket::initSsl(bool server)
initContext(server); initContext(server);
} }
void bool
SecureSocket::loadCertificates(const char* filename) SecureSocket::loadCertificates(String& filename)
{ {
int r = 0; if (filename.empty()) {
r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename, SSL_FILETYPE_PEM); showError("ssl certificate is not specified");
if (r <= 0) { return false;
throwError("could not use ssl certificate"); }
else {
std::ifstream file(filename.c_str());
bool exist = file.good();
file.close();
if (!exist) {
String errorMsg("ssl certificate doesn't exist: ");
errorMsg.append(filename);
showError(errorMsg.c_str());
return false;
}
} }
r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename, SSL_FILETYPE_PEM); int r = 0;
r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM);
if (r <= 0) { if (r <= 0) {
throwError("could not use ssl private key"); showError("could not use ssl certificate");
return false;
}
r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM);
if (r <= 0) {
showError("could not use ssl private key");
return false;
} }
r = SSL_CTX_check_private_key(m_ssl->m_context); r = SSL_CTX_check_private_key(m_ssl->m_context);
if (!r) { if (!r) {
throwError("could not verify ssl private key"); showError("could not verify ssl private key");
return false;
} }
return true;
} }
void void
@ -256,20 +280,29 @@ SecureSocket::secureConnect(int socket)
// tell user and sleep so the socket isn't hammered. // tell user and sleep so the socket isn't hammered.
LOG((CLOG_ERR "failed to connect secure socket")); LOG((CLOG_ERR "failed to connect secure socket"));
LOG((CLOG_INFO "server connection may not be secure")); LOG((CLOG_INFO "server connection may not be secure"));
ARCH->sleep(1); disconnect();
return false;
} }
m_secureReady = !retry; m_secureReady = !retry;
if (m_secureReady) { if (m_secureReady) {
LOG((CLOG_INFO "connected to secure socket")); if (verifyCertFingerprint()) {
showCertificate(); LOG((CLOG_INFO "connected to secure socket"));
if (!showCertificate()) {
disconnect();
}
}
else {
LOG((CLOG_ERR "failed to verity server certificate fingerprint"));
disconnect();
}
} }
return retry; return retry;
} }
void bool
SecureSocket::showCertificate() SecureSocket::showCertificate()
{ {
X509* cert; X509* cert;
@ -284,8 +317,11 @@ SecureSocket::showCertificate()
X509_free(cert); X509_free(cert);
} }
else { else {
throwError("server has no ssl certificate"); showError("server has no ssl certificate");
return false;
} }
return true;
} }
void void
@ -346,30 +382,20 @@ SecureSocket::checkResult(int n, bool& fatal, bool& retry)
if (fatal) { if (fatal) {
showError(); showError();
sendEvent(getEvents()->forISocket().disconnected()); disconnect();
sendEvent(getEvents()->forIStream().inputShutdown());
} }
} }
void void
SecureSocket::showError() SecureSocket::showError(const char* reason)
{ {
String error = getError(); if (reason != NULL) {
if (!error.empty()) { LOG((CLOG_ERR "%s", reason));
LOG((CLOG_ERR "secure socket error: %s", error.c_str()));
} }
}
void
SecureSocket::throwError(const char* reason)
{
String error = getError(); String error = getError();
if (!error.empty()) { if (!error.empty()) {
throw XSocket(synergy::string::sprintf( LOG((CLOG_ERR "%s", error.c_str()));
"%s: %s", reason, error.c_str()));
}
else {
throw XSocket(reason);
} }
} }
@ -388,6 +414,76 @@ SecureSocket::getError()
} }
} }
void
SecureSocket::disconnect()
{
sendEvent(getEvents()->forISocket().disconnected());
sendEvent(getEvents()->forIStream().inputShutdown());
}
void
SecureSocket::formatFingerprint(String& fingerprint, bool hex, bool separator)
{
if (hex) {
// to hexidecimal
synergy::string::toHex(fingerprint, 2);
}
// all uppercase
synergy::string::uppercase(fingerprint);
if (separator) {
// add colon to separate each 2 charactors
size_t separators = fingerprint.size() / 2;
for (size_t i = 1; i < separators; i++) {
fingerprint.insert(i * 3 - 1, ":");
}
}
}
bool
SecureSocket::verifyCertFingerprint()
{
if (m_certFingerprintFilename.empty()) {
return false;
}
// calculate received certificate fingerprint
X509 *cert = cert = SSL_get_peer_certificate(m_ssl->m_ssl);
EVP_MD* tempDigest;
unsigned char tempFingerprint[EVP_MAX_MD_SIZE];
unsigned int tempFingerprintLen;
tempDigest = (EVP_MD*)EVP_sha1();
if (X509_digest(cert, tempDigest, tempFingerprint, &tempFingerprintLen) <= 0) {
return false;
}
// format fingerprint into hexdecimal format with colon separator
String fingerprint(reinterpret_cast<char*>(tempFingerprint), tempFingerprintLen);
formatFingerprint(fingerprint);
LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str()));
// check if this fingerprint exist
String fileLine;
std::ifstream file;
file.open(m_certFingerprintFilename.c_str());
bool isValid = false;
while (!file.eof()) {
getline(file,fileLine);
// example of a fingerprint:A1:B2:C3
if (!fileLine.empty()) {
if (fileLine.compare(fingerprint) == 0) {
isValid = true;
break;
}
}
}
file.close();
return isValid;
}
ISocketMultiplexerJob* ISocketMultiplexerJob*
SecureSocket::serviceConnect(ISocketMultiplexerJob* job, SecureSocket::serviceConnect(ISocketMultiplexerJob* job,
bool, bool write, bool error) bool, bool write, bool error)

View File

@ -43,13 +43,14 @@ public:
void secureConnect(); void secureConnect();
void secureAccept(); void secureAccept();
void setFingerprintFilename(String& f) { m_certFingerprintFilename = f; }
bool isReady() const { return m_secureReady; } bool isReady() const { return m_secureReady; }
bool isSecureReady(); bool isSecureReady();
bool isSecure() { return true; } bool isSecure() { return true; }
UInt32 secureRead(void* buffer, UInt32 n); UInt32 secureRead(void* buffer, UInt32 n);
UInt32 secureWrite(const void* buffer, UInt32 n); UInt32 secureWrite(const void* buffer, UInt32 n);
void initSsl(bool server); void initSsl(bool server);
void loadCertificates(const char* CertFile); bool loadCertificates(String& CertFile);
private: private:
// SSL // SSL
@ -57,11 +58,15 @@ private:
void createSSL(); void createSSL();
bool secureAccept(int s); bool secureAccept(int s);
bool secureConnect(int s); bool secureConnect(int s);
void showCertificate(); bool showCertificate();
void checkResult(int n, bool& fatal, bool& retry); void checkResult(int n, bool& fatal, bool& retry);
void showError(); void showError(const char* reason = NULL);
void throwError(const char* reason);
String getError(); String getError();
void disconnect();
void formatFingerprint(String& fingerprint,
bool hex = true,
bool separator = true);
bool verifyCertFingerprint();
ISocketMultiplexerJob* ISocketMultiplexerJob*
serviceConnect(ISocketMultiplexerJob*, serviceConnect(ISocketMultiplexerJob*,
@ -74,4 +79,5 @@ private:
private: private:
Ssl* m_ssl; Ssl* m_ssl;
bool m_secureReady; bool m_secureReady;
String m_certFingerprintFilename;
}; };

View File

@ -89,6 +89,10 @@ ArgParser::parseClientArgs(ClientArgs& args, int argc, const char* const* argv)
// define scroll // define scroll
args.m_yscroll = atoi(argv[++i]); args.m_yscroll = atoi(argv[++i]);
} }
else if (isArg(i, argc, argv, NULL, "--certificate-fingerprint", 1)) {
// define scroll
args.m_certFingerprintFilename = argv[++i];
}
else { else {
if (i + 1 == argc) { if (i + 1 == argc) {
args.m_synergyAddress = argv[i]; args.m_synergyAddress = argv[i];

View File

@ -24,25 +24,27 @@ class ArgsBase {
public: public:
ArgsBase(); ArgsBase();
virtual ~ArgsBase(); virtual ~ArgsBase();
bool m_daemon;
bool m_backend; public:
bool m_restartable; bool m_daemon;
bool m_noHooks; bool m_backend;
const char* m_pname; bool m_restartable;
const char* m_logFilter; bool m_noHooks;
const char* m_logFile; const char* m_pname;
const char* m_display; const char* m_logFilter;
String m_name; const char* m_logFile;
bool m_disableTray; const char* m_display;
bool m_enableIpc; String m_name;
bool m_enableDragDrop; bool m_disableTray;
bool m_enableIpc;
bool m_enableDragDrop;
#if SYSAPI_WIN32 #if SYSAPI_WIN32
bool m_debugServiceWait; bool m_debugServiceWait;
bool m_pauseOnExit; bool m_pauseOnExit;
bool m_stopOnDeskSwitch; bool m_stopOnDeskSwitch;
#endif #endif
#if WINAPI_XWINDOWS #if WINAPI_XWINDOWS
bool m_disableXInitThreads; bool m_disableXInitThreads;
#endif #endif
bool m_shouldExit; bool m_shouldExit;
String m_synergyAddress; String m_synergyAddress;

View File

@ -342,8 +342,7 @@ ClientApp::openClient(const String& name, const NetworkAddress& address,
address, address,
new TCPSocketFactory(m_events, getSocketMultiplexer()), new TCPSocketFactory(m_events, getSocketMultiplexer()),
screen, screen,
args().m_enableDragDrop, args());
args().m_enableCrypto);
try { try {
m_events->adoptHandler( m_events->adoptHandler(

View File

@ -18,6 +18,7 @@
#include "synergy/ClientArgs.h" #include "synergy/ClientArgs.h"
ClientArgs::ClientArgs() : ClientArgs::ClientArgs() :
m_yscroll(0) m_yscroll(0),
m_certFingerprintFilename()
{ {
} }

View File

@ -26,5 +26,6 @@ public:
ClientArgs(); ClientArgs();
public: public:
int m_yscroll; int m_yscroll;
String m_certFingerprintFilename;
}; };

View File

@ -140,7 +140,11 @@ TEST_F(NetworkTests, sendToClient_mockData)
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, true, false);
ClientArgs args;
args.m_enableDragDrop = true;
args.m_enableCrypto = false;
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveCompleted(), &client, m_events.forIScreen().fileRecieveCompleted(), &client,
@ -192,7 +196,11 @@ TEST_F(NetworkTests, sendToClient_mockFile)
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, true, false);
ClientArgs args;
args.m_enableDragDrop = true;
args.m_enableCrypto = false;
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveCompleted(), &client, m_events.forIScreen().fileRecieveCompleted(), &client,
@ -238,7 +246,10 @@ TEST_F(NetworkTests, sendToServer_mockData)
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, true, false); ClientArgs args;
args.m_enableDragDrop = true;
args.m_enableCrypto = false;
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forClientListener().connected(), &listener, m_events.forClientListener().connected(), &listener,
@ -290,8 +301,11 @@ TEST_F(NetworkTests, sendToServer_mockFile)
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, true, false); ClientArgs args;
args.m_enableDragDrop = true;
args.m_enableCrypto = false;
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forClientListener().connected(), &listener, m_events.forClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(

View File

@ -53,3 +53,32 @@ TEST(StringTests, sprintf)
EXPECT_EQ("answer=42", result); EXPECT_EQ("answer=42", result);
} }
TEST(StringTests, toHex)
{
String subject = "foobar";
int width = 2;
string::toHex(subject, width);
EXPECT_EQ("666f6f626172", subject);
}
TEST(StringTests, uppercase)
{
String subject = "12foo3BaR";
string::uppercase(subject);
EXPECT_EQ("12FOO3BAR", subject);
}
TEST(StringTests, removeChar)
{
String subject = "foobar";
const char c = 'o';
string::removeChar(subject, c);
EXPECT_EQ("fbar", subject);
}