diff options
| author | 2018-04-25 18:07:30 -0400 | |
|---|---|---|
| committer | 2018-04-25 18:07:30 -0400 | |
| commit | 9b1b081cfdb1c0fb6457278775e0823f8bc10f62 (patch) | |
| tree | ce8840148d8445055ba9e4f12263b2208f234c16 /src/test | |
Import Upstream version 2.0.0+dfsgupstream/2.0.0+dfsg
Diffstat (limited to 'src/test')
49 files changed, 5462 insertions, 0 deletions
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt new file mode 100644 index 0000000..daecb31 --- /dev/null +++ b/src/test/CMakeLists.txt @@ -0,0 +1,33 @@ +# barrier -- mouse and keyboard sharing utility +# Copyright (C) 2012-2016 Symless Ltd. +# Copyright (C) 2011 Nick Bolton +# +# This package is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# found in the file LICENSE that should have accompanied this file. +# +# This package is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +include_directories( + ../../ext/gtest + ../../ext/gtest/include + ../../ext/gmock + ../../ext/gmock/include) + +add_library(gtest STATIC ../../ext/gtest/src/gtest-all.cc) +add_library(gmock STATIC ../../ext/gmock/src/gmock-all.cc) + +if (UNIX) + # ignore warnings in gtest and gmock + set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w") + set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w") +endif() + +add_subdirectory(integtests) +add_subdirectory(unittests) diff --git a/src/test/global/TestEventQueue.cpp b/src/test/global/TestEventQueue.cpp new file mode 100644 index 0000000..d202922 --- /dev/null +++ b/src/test/global/TestEventQueue.cpp @@ -0,0 +1,53 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2013-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "test/global/TestEventQueue.h" + +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "base/SimpleEventQueueBuffer.h" +#include "common/stdexcept.h" + +void +TestEventQueue::raiseQuitEvent() +{ + addEvent(Event(Event::kQuit)); +} + +void +TestEventQueue::initQuitTimeout(double timeout) +{ + assert(m_quitTimeoutTimer == nullptr); + m_quitTimeoutTimer = newOneShotTimer(timeout, NULL); + adoptHandler(Event::kTimer, m_quitTimeoutTimer, + new TMethodEventJob<TestEventQueue>( + this, &TestEventQueue::handleQuitTimeout)); +} + +void +TestEventQueue::cleanupQuitTimeout() +{ + removeHandler(Event::kTimer, m_quitTimeoutTimer); + delete m_quitTimeoutTimer; + m_quitTimeoutTimer = nullptr; +} + +void +TestEventQueue::handleQuitTimeout(const Event&, void* vclient) +{ + throw std::runtime_error("test event queue timeout"); +} diff --git a/src/test/global/TestEventQueue.h b/src/test/global/TestEventQueue.h new file mode 100644 index 0000000..a6cf0ca --- /dev/null +++ b/src/test/global/TestEventQueue.h @@ -0,0 +1,38 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2013-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "base/EventQueue.h" + +class EventQueueTimer; + +class TestEventQueue : public EventQueue { +public: + TestEventQueue() : m_quitTimeoutTimer(nullptr) { } + + void handleQuitTimeout(const Event&, void* vclient); + void raiseQuitEvent(); + void initQuitTimeout(double timeout); + void cleanupQuitTimeout(); + +private: + void timeoutThread(void*); + +private: + EventQueueTimer* m_quitTimeoutTimer; +}; diff --git a/src/test/global/gmock.h b/src/test/global/gmock.h new file mode 100644 index 0000000..64597f4 --- /dev/null +++ b/src/test/global/gmock.h @@ -0,0 +1,32 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +// HACK: gcc on osx106 doesn't give you an easy way to hide warnings +// from included headers, so use the system_header pragma. the downside +// is that everything in the header file following this also has warnings +// ignored, so we need to put it in a separate header file. +#if __APPLE__ +# pragma GCC system_header +#endif + +// gmock includes gtest which has a warning on osx106 (signed/unsigned +// int compare), so include our special header here first to silence +// the warning. +#include "test/global/gtest.h" +#include <gmock/gmock.h> diff --git a/src/test/global/gtest.h b/src/test/global/gtest.h new file mode 100644 index 0000000..0b2acbc --- /dev/null +++ b/src/test/global/gtest.h @@ -0,0 +1,29 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +// HACK: gcc on osx106 doesn't give you an easy way to hide warnings +// from included headers, so use the system_header pragma. the downside +// is that everything in the header file following this also has warnings +// ignored, so we need to put it in a separate header file. +#if __APPLE__ +# pragma GCC system_header +#endif + +// gtest has a warning on osx106 (signed/unsigned int compare). +#include <gtest/gtest.h> diff --git a/src/test/guitests/guitests.pro b/src/test/guitests/guitests.pro new file mode 100644 index 0000000..3be7e0d --- /dev/null +++ b/src/test/guitests/guitests.pro @@ -0,0 +1,16 @@ +QT += network
+QT -= gui
+TARGET = guitests
+CONFIG += qtestlib
+CONFIG += console
+CONFIG -= app_bundle
+TEMPLATE = app
+INCLUDEPATH += ../../gui/src
+SOURCES += src/main.cpp \
+ src/VersionCheckerTests.cpp
+HEADERS += src/VersionCheckerTests.h
+win32 {
+ Debug:DESTDIR = ../../../bin/Debug
+ Release:DESTDIR = ../../../bin/Release
+}
+else:DESTDIR = ../../../bin
diff --git a/src/test/guitests/src/VersionCheckerTests.cpp b/src/test/guitests/src/VersionCheckerTests.cpp new file mode 100644 index 0000000..0efc5f9 --- /dev/null +++ b/src/test/guitests/src/VersionCheckerTests.cpp @@ -0,0 +1,47 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2012 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "VersionCheckerTests.h" +#include "VersionChecker.cpp" +#include "../../gui/tmp/release/moc_VersionChecker.cpp" + +#include <QtTest/QTest> + +void VersionCheckerTests::compareVersions() +{ + VersionChecker versionChecker; + + // compare majors + QCOMPARE(versionChecker.compareVersions("1.0.0", "2.0.0"), 1); + QCOMPARE(versionChecker.compareVersions("2.0.0", "1.0.0"), -1); + QCOMPARE(versionChecker.compareVersions("1.0.0", "1.0.0"), 0); + QCOMPARE(versionChecker.compareVersions("1.4.8", "2.4.7"), 1); + QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1); + + // compare minors + QCOMPARE(versionChecker.compareVersions("1.3.0", "1.4.0"), 1); + QCOMPARE(versionChecker.compareVersions("1.4.0", "1.3.0"), -1); + QCOMPARE(versionChecker.compareVersions("1.4.0", "1.4.0"), 0); + QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1); + QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1); + + // compare revs + QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.8"), 1); + QCOMPARE(versionChecker.compareVersions("1.4.8", "1.4.7"), -1); + QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.7"), 0); +} diff --git a/src/test/guitests/src/VersionCheckerTests.h b/src/test/guitests/src/VersionCheckerTests.h new file mode 100644 index 0000000..7884f3a --- /dev/null +++ b/src/test/guitests/src/VersionCheckerTests.h @@ -0,0 +1,28 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2012 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "qobject.h" + +class VersionCheckerTests : public QObject +{ + Q_OBJECT +private slots: + void compareVersions(); +}; diff --git a/src/test/guitests/src/main.cpp b/src/test/guitests/src/main.cpp new file mode 100644 index 0000000..2ff6e72 --- /dev/null +++ b/src/test/guitests/src/main.cpp @@ -0,0 +1,26 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2012 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <QtTest/QTest> +#include "VersionCheckerTests.h" + +int main(int argc, char *argv[]) +{ + VersionCheckerTests versionCheckerTests; + QTest::qExec(&versionCheckerTests, argc, argv); +} diff --git a/src/test/integtests/CMakeLists.txt b/src/test/integtests/CMakeLists.txt new file mode 100644 index 0000000..a412ecc --- /dev/null +++ b/src/test/integtests/CMakeLists.txt @@ -0,0 +1,71 @@ +# barrier -- mouse and keyboard sharing utility +# Copyright (C) 2012-2016 Symless Ltd. +# Copyright (C) 2009 Nick Bolton +# +# This package is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# found in the file LICENSE that should have accompanied this file. +# +# This package is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +file(GLOB_RECURSE headers "*.h") +file(GLOB_RECURSE sources "*.cpp") + +# remove platform files (specific platform added later). +file(GLOB_RECURSE remove_platform "platform/*") +list(REMOVE_ITEM headers ${remove_platform}) +list(REMOVE_ITEM sources ${remove_platform}) + +# platform +if (WIN32) + file(GLOB platform_sources "platform/MSWindows*.cpp") + file(GLOB platform_headers "platform/MSWindows*.h") +elseif (APPLE) + file(GLOB platform_sources "platform/OSX*.cpp") + file(GLOB platform_headers "platform/OSX*.h") +elseif (UNIX) + file(GLOB platform_sources "platform/XWindows*.cpp") + file(GLOB platform_headers "platform/XWindows*.h") +endif() + +list(APPEND sources ${platform_sources}) +list(APPEND headers ${platform_headers}) + +file(GLOB_RECURSE global_headers "../../test/global/*.h") +file(GLOB_RECURSE global_sources "../../test/global/*.cpp") + +list(APPEND headers ${global_headers}) +list(APPEND sources ${global_sources}) + +file(GLOB_RECURSE mock_headers "../../test/mock/*.h") +file(GLOB_RECURSE mock_sources "../../test/mock/*.cpp") + +list(APPEND headers ${mock_headers}) +list(APPEND sources ${mock_sources}) + +if (BARRIER_ADD_HEADERS) + list(APPEND sources ${headers}) +endif() + +include_directories( + ../../ + ../../lib/ + ../../../ext/gtest/include + ../../../ext/gmock/include +) + +if (UNIX) + include_directories( + ../../.. + ) +endif() + +add_executable(integtests ${sources}) +target_link_libraries(integtests + arch base client common io ipc mt net platform server barrier gtest gmock ${libs} ${OPENSSL_LIBS}) diff --git a/src/test/integtests/Main.cpp b/src/test/integtests/Main.cpp new file mode 100644 index 0000000..76b42b6 --- /dev/null +++ b/src/test/integtests/Main.cpp @@ -0,0 +1,108 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "arch/Arch.h" +#include "base/Log.h" + +#if SYSAPI_WIN32 +#include "arch/win32/ArchMiscWindows.h" +#endif + +#include "test/global/gtest.h" +#include <iostream> +#include <fstream> + +#define LOCK_TIMEOUT 30 + +using namespace std; + +void lock(string lockFile); +void unlock(string lockFile); + +int +main(int argc, char **argv) +{ +#if SYSAPI_WIN32 + // record window instance for tray icon, etc + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); +#endif + + Arch arch; + arch.init(); + + Log log; + log.setFilter(kDEBUG2); + + string lockFile; + for (int i = 0; i < argc; i++) { + if (string(argv[i]).compare("--lock-file") == 0) { + lockFile = argv[i + 1]; + } + } + + if (!lockFile.empty()) { + lock(lockFile); + } + + + testing::InitGoogleTest(&argc, argv); + + int result = RUN_ALL_TESTS(); + + if (!lockFile.empty()) { + unlock(lockFile); + } + + // gtest seems to randomly finish with error codes (e.g. -1, -1073741819) + // even when no tests have failed. not sure what causes this, but it + // happens on all platforms and keeps leading to false positives. + // according to the documentation, 1 is a failure, so we should be + // able to trust that code. + return (result == 1) ? 1 : 0; +} + +void +lock(string lockFile) +{ + double start = ARCH->time(); + + // keep checking until timeout is reached. + while ((ARCH->time() - start) < LOCK_TIMEOUT) { + + ifstream is(lockFile.c_str()); + bool noLock = !is; + is.close(); + + if (noLock) { + break; + } + + // check every second if file has gone. + ARCH->sleep(1); + } + + // write empty lock file. + ofstream os(lockFile.c_str()); + os.close(); +} + +void +unlock(string lockFile) +{ + remove(lockFile.c_str()); +} diff --git a/src/test/integtests/arch/ArchInternetTests.cpp b/src/test/integtests/arch/ArchInternetTests.cpp new file mode 100644 index 0000000..722df2f --- /dev/null +++ b/src/test/integtests/arch/ArchInternetTests.cpp @@ -0,0 +1,37 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "arch/Arch.h" + +#include "test/global/gtest.h" + +#define TEST_URL "https://symless.com/tests/?testString" +//#define TEST_URL "http://localhost/barrier/tests/?testString" + +TEST(ArchInternetTests, get) +{ + ARCH_INTERNET internet; + String result = internet.get(TEST_URL); + ASSERT_EQ("Hello world!", result); +} + +TEST(ArchInternetTests, urlEncode) +{ + ARCH_INTERNET internet; + String result = internet.urlEncode("hello=+&world"); + ASSERT_EQ("hello%3D%2B%26world", result); +} diff --git a/src/test/integtests/ipc/IpcTests.cpp b/src/test/integtests/ipc/IpcTests.cpp new file mode 100644 index 0000000..a0ee241 --- /dev/null +++ b/src/test/integtests/ipc/IpcTests.cpp @@ -0,0 +1,211 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2012 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// TODO: fix, tests failing intermittently on mac. +#ifndef WINAPI_CARBON + +#define TEST_ENV + +#include "test/global/TestEventQueue.h" +#include "ipc/IpcServer.h" +#include "ipc/IpcClient.h" +#include "ipc/IpcServerProxy.h" +#include "ipc/IpcMessage.h" +#include "ipc/IpcClientProxy.h" +#include "ipc/Ipc.h" +#include "net/SocketMultiplexer.h" +#include "mt/Thread.h" +#include "arch/Arch.h" +#include "base/TMethodJob.h" +#include "base/String.h" +#include "base/Log.h" +#include "base/EventQueue.h" +#include "base/TMethodEventJob.h" + +#include "test/global/gtest.h" + +#define TEST_IPC_PORT 24802 + +class IpcTests : public ::testing::Test +{ +public: + IpcTests(); + virtual ~IpcTests(); + + void connectToServer_handleMessageReceived(const Event&, void*); + void sendMessageToServer_serverHandleMessageReceived(const Event&, void*); + void sendMessageToClient_serverHandleClientConnected(const Event&, void*); + void sendMessageToClient_clientHandleMessageReceived(const Event&, void*); + +public: + SocketMultiplexer m_multiplexer; + bool m_connectToServer_helloMessageReceived; + bool m_connectToServer_hasClientNode; + IpcServer* m_connectToServer_server; + String m_sendMessageToServer_receivedString; + String m_sendMessageToClient_receivedString; + IpcClient* m_sendMessageToServer_client; + IpcServer* m_sendMessageToClient_server; + TestEventQueue m_events; + +}; + +TEST_F(IpcTests, connectToServer) +{ + SocketMultiplexer socketMultiplexer; + IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); + server.listen(); + m_connectToServer_server = &server; + + m_events.adoptHandler( + m_events.forIpcServer().messageReceived(), &server, + new TMethodEventJob<IpcTests>( + this, &IpcTests::connectToServer_handleMessageReceived)); + + IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); + client.connect(); + + m_events.initQuitTimeout(5); + m_events.loop(); + m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); + m_events.cleanupQuitTimeout(); + + EXPECT_EQ(true, m_connectToServer_helloMessageReceived); + EXPECT_EQ(true, m_connectToServer_hasClientNode); +} + +TEST_F(IpcTests, sendMessageToServer) +{ + SocketMultiplexer socketMultiplexer; + IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); + server.listen(); + + // event handler sends "test" command to server. + m_events.adoptHandler( + m_events.forIpcServer().messageReceived(), &server, + new TMethodEventJob<IpcTests>( + this, &IpcTests::sendMessageToServer_serverHandleMessageReceived)); + + IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); + client.connect(); + m_sendMessageToServer_client = &client; + + m_events.initQuitTimeout(5); + m_events.loop(); + m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); + m_events.cleanupQuitTimeout(); + + EXPECT_EQ("test", m_sendMessageToServer_receivedString); +} + +TEST_F(IpcTests, sendMessageToClient) +{ + SocketMultiplexer socketMultiplexer; + IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); + server.listen(); + m_sendMessageToClient_server = &server; + + // event handler sends "test" log line to client. + m_events.adoptHandler( + m_events.forIpcServer().messageReceived(), &server, + new TMethodEventJob<IpcTests>( + this, &IpcTests::sendMessageToClient_serverHandleClientConnected)); + + IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); + client.connect(); + + m_events.adoptHandler( + m_events.forIpcClient().messageReceived(), &client, + new TMethodEventJob<IpcTests>( + this, &IpcTests::sendMessageToClient_clientHandleMessageReceived)); + + m_events.initQuitTimeout(5); + m_events.loop(); + m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); + m_events.removeHandler(m_events.forIpcClient().messageReceived(), &client); + m_events.cleanupQuitTimeout(); + + EXPECT_EQ("test", m_sendMessageToClient_receivedString); +} + +IpcTests::IpcTests() : +m_connectToServer_helloMessageReceived(false), +m_connectToServer_hasClientNode(false), +m_connectToServer_server(nullptr), +m_sendMessageToClient_server(nullptr), +m_sendMessageToServer_client(nullptr) +{ +} + +IpcTests::~IpcTests() +{ +} + +void +IpcTests::connectToServer_handleMessageReceived(const Event& e, void*) +{ + IpcMessage* m = static_cast<IpcMessage*>(e.getDataObject()); + if (m->type() == kIpcHello) { + m_connectToServer_hasClientNode = + m_connectToServer_server->hasClients(kIpcClientNode); + m_connectToServer_helloMessageReceived = true; + m_events.raiseQuitEvent(); + } +} + +void +IpcTests::sendMessageToServer_serverHandleMessageReceived(const Event& e, void*) +{ + IpcMessage* m = static_cast<IpcMessage*>(e.getDataObject()); + if (m->type() == kIpcHello) { + LOG((CLOG_DEBUG "client said hello, sending test to server")); + IpcCommandMessage m("test", true); + m_sendMessageToServer_client->send(m); + } + else if (m->type() == kIpcCommand) { + IpcCommandMessage* cm = static_cast<IpcCommandMessage*>(m); + LOG((CLOG_DEBUG "got ipc command message, %d", cm->command().c_str())); + m_sendMessageToServer_receivedString = cm->command(); + m_events.raiseQuitEvent(); + } +} + +void +IpcTests::sendMessageToClient_serverHandleClientConnected(const Event& e, void*) +{ + IpcMessage* m = static_cast<IpcMessage*>(e.getDataObject()); + if (m->type() == kIpcHello) { + LOG((CLOG_DEBUG "client said hello, sending test to client")); + IpcLogLineMessage m("test"); + m_sendMessageToClient_server->send(m, kIpcClientNode); + } +} + +void +IpcTests::sendMessageToClient_clientHandleMessageReceived(const Event& e, void*) +{ + IpcMessage* m = static_cast<IpcMessage*>(e.getDataObject()); + if (m->type() == kIpcLogLine) { + IpcLogLineMessage* llm = static_cast<IpcLogLineMessage*>(m); + LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str())); + m_sendMessageToClient_receivedString = llm->logLine(); + m_events.raiseQuitEvent(); + } +} + +#endif // WINAPI_CARBON diff --git a/src/test/integtests/net/NetworkTests.cpp b/src/test/integtests/net/NetworkTests.cpp new file mode 100644 index 0000000..4a9a9f0 --- /dev/null +++ b/src/test/integtests/net/NetworkTests.cpp @@ -0,0 +1,525 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2013-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// TODO: fix, tests failing intermittently on mac. +#ifndef WINAPI_CARBON + +#define TEST_ENV + +#include "test/mock/server/MockConfig.h" +#include "test/mock/server/MockPrimaryClient.h" +#include "test/mock/barrier/MockScreen.h" +#include "test/mock/server/MockInputFilter.h" +#include "test/global/TestEventQueue.h" +#include "server/Server.h" +#include "server/ClientListener.h" +#include "server/ClientProxy.h" +#include "client/Client.h" +#include "barrier/FileChunk.h" +#include "barrier/StreamChunker.h" +#include "net/SocketMultiplexer.h" +#include "net/NetworkAddress.h" +#include "net/TCPSocketFactory.h" +#include "mt/Thread.h" +#include "base/TMethodEventJob.h" +#include "base/TMethodJob.h" +#include "base/Log.h" +#include "common/stdexcept.h" + +#include "test/global/gtest.h" +#include <sstream> +#include <fstream> +#include <iostream> +#include <stdio.h> + +using namespace std; +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::Invoke; + +#define TEST_PORT 24803 +#define TEST_HOST "localhost" + +const size_t kMockDataSize = 1024 * 1024 * 10; // 10MB +const UInt16 kMockDataChunkIncrement = 1024; // 1KB +const char* kMockFilename = "NetworkTests.mock"; +const size_t kMockFileSize = 1024 * 1024 * 10; // 10MB + +void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h); +void getCursorPos(SInt32& x, SInt32& y); +UInt8* newMockData(size_t size); +void createFile(fstream& file, const char* filename, size_t size); + +class NetworkTests : public ::testing::Test +{ +public: + NetworkTests() : + m_mockData(NULL), + m_mockDataSize(0), + m_mockFileSize(0) + { + m_mockData = newMockData(kMockDataSize); + createFile(m_mockFile, kMockFilename, kMockFileSize); + } + + ~NetworkTests() + { + remove(kMockFilename); + delete[] m_mockData; + } + + void sendMockData(void* eventTarget); + + void sendToClient_mockData_handleClientConnected(const Event&, void* vlistener); + void sendToClient_mockData_fileRecieveCompleted(const Event&, void*); + + void sendToClient_mockFile_handleClientConnected(const Event&, void* vlistener); + void sendToClient_mockFile_fileRecieveCompleted(const Event& event, void*); + + void sendToServer_mockData_handleClientConnected(const Event&, void* vlistener); + void sendToServer_mockData_fileRecieveCompleted(const Event& event, void*); + + void sendToServer_mockFile_handleClientConnected(const Event&, void* vlistener); + void sendToServer_mockFile_fileRecieveCompleted(const Event& event, void*); + +public: + TestEventQueue m_events; + UInt8* m_mockData; + size_t m_mockDataSize; + fstream m_mockFile; + size_t m_mockFileSize; +}; + +TEST_F(NetworkTests, sendToClient_mockData) +{ + // server and client + NetworkAddress serverAddress(TEST_HOST, TEST_PORT); + + serverAddress.resolve(); + + // server + SocketMultiplexer serverSocketMultiplexer; + TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); + NiceMock<MockScreen> serverScreen; + NiceMock<MockPrimaryClient> primaryClient; + NiceMock<MockConfig> serverConfig; + NiceMock<MockInputFilter> serverInputFilter; + + m_events.adoptHandler( + m_events.forClientListener().connected(), &listener, + new TMethodEventJob<NetworkTests>( + this, &NetworkTests::sendToClient_mockData_handleClientConnected, &listener)); + + ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); + ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); + + ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); + server.m_mock = true; + listener.setServer(&server); + + // client + NiceMock<MockScreen> clientScreen; + SocketMultiplexer clientSocketMultiplexer; + TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); + + ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); + ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); + + + ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); + + m_events.adoptHandler( + m_events.forFile().fileRecieveCompleted(), &client, + new TMethodEventJob<NetworkTests>( + this, &NetworkTests::sendToClient_mockData_fileRecieveCompleted)); + + client.connect(); + + m_events.initQuitTimeout(10); + m_events.loop(); + m_events.removeHandler(m_events.forClientListener().connected(), &listener); + m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &client); + m_events.cleanupQuitTimeout(); +} + +TEST_F(NetworkTests, sendToClient_mockFile) +{ + // server and client + NetworkAddress serverAddress(TEST_HOST, TEST_PORT); + + serverAddress.resolve(); + + // server + SocketMultiplexer serverSocketMultiplexer; + TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); + NiceMock<MockScreen> serverScreen; + NiceMock<MockPrimaryClient> primaryClient; + NiceMock<MockConfig> serverConfig; + NiceMock<MockInputFilter> serverInputFilter; + + m_events.adoptHandler( + m_events.forClientListener().connected(), &listener, + new TMethodEventJob<NetworkTests>( + this, &NetworkTests::sendToClient_mockFile_handleClientConnected, &listener)); + + ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); + ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); + + ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); + server.m_mock = true; + listener.setServer(&server); + + // client + NiceMock<MockScreen> clientScreen; + SocketMultiplexer clientSocketMultiplexer; + TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); + + ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); + ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); + + + ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); + + m_events.adoptHandler( + m_events.forFile().fileRecieveCompleted(), &client, + new TMethodEventJob<NetworkTests>( + this, &NetworkTests::sendToClient_mockFile_fileRecieveCompleted)); + + client.connect(); + + m_events.initQuitTimeout(10); + m_events.loop(); + m_events.removeHandler(m_events.forClientListener().connected(), &listener); + m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &client); + m_events.cleanupQuitTimeout(); +} + +TEST_F(NetworkTests, sendToServer_mockData) +{ + // server and client + NetworkAddress serverAddress(TEST_HOST, TEST_PORT); + serverAddress.resolve(); + + // server + SocketMultiplexer serverSocketMultiplexer; + TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); + NiceMock<MockScreen> serverScreen; + NiceMock<MockPrimaryClient> primaryClient; + NiceMock<MockConfig> serverConfig; + NiceMock<MockInputFilter> serverInputFilter; + + ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); + ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); + + ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); + server.m_mock = true; + listener.setServer(&server); + + // client + NiceMock<MockScreen> clientScreen; + SocketMultiplexer clientSocketMultiplexer; + TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); + + ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); + ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); + + ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); + + m_events.adoptHandler( + m_events.forClientListener().connected(), &listener, + new TMethodEventJob<NetworkTests>( + this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client)); + + m_events.adoptHandler( + m_events.forFile().fileRecieveCompleted(), &server, + new TMethodEventJob<NetworkTests>( + this, &NetworkTests::sendToServer_mockData_fileRecieveCompleted)); + + client.connect(); + + m_events.initQuitTimeout(10); + m_events.loop(); + m_events.removeHandler(m_events.forClientListener().connected(), &listener); + m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &server); + m_events.cleanupQuitTimeout(); +} + +TEST_F(NetworkTests, sendToServer_mockFile) +{ + // server and client + NetworkAddress serverAddress(TEST_HOST, TEST_PORT); + + serverAddress.resolve(); + + // server + SocketMultiplexer serverSocketMultiplexer; + TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); + NiceMock<MockScreen> serverScreen; + NiceMock<MockPrimaryClient> primaryClient; + NiceMock<MockConfig> serverConfig; + NiceMock<MockInputFilter> serverInputFilter; + + ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); + ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); + + ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); + server.m_mock = true; + listener.setServer(&server); + + // client + NiceMock<MockScreen> clientScreen; + SocketMultiplexer clientSocketMultiplexer; + TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); + + ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); + ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); + + ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); + + m_events.adoptHandler( + m_events.forClientListener().connected(), &listener, + new TMethodEventJob<NetworkTests>( + this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client)); + + m_events.adoptHandler( + m_events.forFile().fileRecieveCompleted(), &server, + new TMethodEventJob<NetworkTests>( + this, &NetworkTests::sendToServer_mockFile_fileRecieveCompleted)); + + client.connect(); + + m_events.initQuitTimeout(10); + m_events.loop(); + m_events.removeHandler(m_events.forClientListener().connected(), &listener); + m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &server); + m_events.cleanupQuitTimeout(); +} + +void +NetworkTests::sendToClient_mockData_handleClientConnected(const Event&, void* vlistener) +{ + ClientListener* listener = static_cast<ClientListener*>(vlistener); + Server* server = listener->getServer(); + + ClientProxy* client = listener->getNextClient(); + if (client == NULL) { + throw runtime_error("client is null"); + } + + BaseClientProxy* bcp = client; + server->adoptClient(bcp); + server->setActive(bcp); + + sendMockData(server); +} + +void +NetworkTests::sendToClient_mockData_fileRecieveCompleted(const Event& event, void*) +{ + Client* client = static_cast<Client*>(event.getTarget()); + EXPECT_TRUE(client->isReceivedFileSizeValid()); + + m_events.raiseQuitEvent(); +} + +void +NetworkTests::sendToClient_mockFile_handleClientConnected(const Event&, void* vlistener) +{ + ClientListener* listener = static_cast<ClientListener*>(vlistener); + Server* server = listener->getServer(); + + ClientProxy* client = listener->getNextClient(); + if (client == NULL) { + throw runtime_error("client is null"); + } + + BaseClientProxy* bcp = client; + server->adoptClient(bcp); + server->setActive(bcp); + + server->sendFileToClient(kMockFilename); +} + +void +NetworkTests::sendToClient_mockFile_fileRecieveCompleted(const Event& event, void*) +{ + Client* client = static_cast<Client*>(event.getTarget()); + EXPECT_TRUE(client->isReceivedFileSizeValid()); + + m_events.raiseQuitEvent(); +} + +void +NetworkTests::sendToServer_mockData_handleClientConnected(const Event&, void* vclient) +{ + Client* client = static_cast<Client*>(vclient); + sendMockData(client); +} + +void +NetworkTests::sendToServer_mockData_fileRecieveCompleted(const Event& event, void*) +{ + Server* server = static_cast<Server*>(event.getTarget()); + EXPECT_TRUE(server->isReceivedFileSizeValid()); + + m_events.raiseQuitEvent(); +} + +void +NetworkTests::sendToServer_mockFile_handleClientConnected(const Event&, void* vclient) +{ + Client* client = static_cast<Client*>(vclient); + client->sendFileToServer(kMockFilename); +} + +void +NetworkTests::sendToServer_mockFile_fileRecieveCompleted(const Event& event, void*) +{ + Server* server = static_cast<Server*>(event.getTarget()); + EXPECT_TRUE(server->isReceivedFileSizeValid()); + + m_events.raiseQuitEvent(); +} + +void +NetworkTests::sendMockData(void* eventTarget) +{ + // send first message (file size) + String size = barrier::string::sizeTypeToString(kMockDataSize); + FileChunk* sizeMessage = FileChunk::start(size); + + m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, sizeMessage)); + + // send chunk messages with incrementing chunk size + size_t lastSize = 0; + size_t sentLength = 0; + while (true) { + size_t dataSize = lastSize + kMockDataChunkIncrement; + + // make sure we don't read too much from the mock data. + if (sentLength + dataSize > kMockDataSize) { + dataSize = kMockDataSize - sentLength; + } + + // first byte is the chunk mark, last is \0 + FileChunk* chunk = FileChunk::data(m_mockData, dataSize); + m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, chunk)); + + sentLength += dataSize; + lastSize = dataSize; + + if (sentLength == kMockDataSize) { + break; + } + + } + + // send last message + FileChunk* transferFinished = FileChunk::end(); + m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, transferFinished)); +} + +UInt8* +newMockData(size_t size) +{ + UInt8* buffer = new UInt8[size]; + + UInt8* data = buffer; + const UInt8 head[] = "mock head... "; + size_t headSize = sizeof(head) - 1; + const UInt8 tail[] = "... mock tail"; + size_t tailSize = sizeof(tail) - 1; + const UInt8 barrierRocks[] = "barrier\0 rocks! "; + size_t barrierRocksSize = sizeof(barrierRocks) - 1; + + memcpy(data, head, headSize); + data += headSize; + + size_t times = (size - headSize - tailSize) / barrierRocksSize; + for (size_t i = 0; i < times; ++i) { + memcpy(data, barrierRocks, barrierRocksSize); + data += barrierRocksSize; + } + + size_t remainder = (size - headSize - tailSize) % barrierRocksSize; + if (remainder != 0) { + memset(data, '.', remainder); + data += remainder; + } + + memcpy(data, tail, tailSize); + return buffer; +} + +void +createFile(fstream& file, const char* filename, size_t size) +{ + UInt8* buffer = newMockData(size); + + file.open(filename, ios::out | ios::binary); + if (!file.is_open()) { + throw runtime_error("file not open"); + } + + file.write(reinterpret_cast<char*>(buffer), size); + file.close(); + + delete[] buffer; +} + +void +getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) +{ + x = 0; + y = 0; + w = 1; + h = 1; +} + +void +getCursorPos(SInt32& x, SInt32& y) +{ + x = 0; + y = 0; +} + +#endif // WINAPI_CARBON diff --git a/src/test/integtests/platform/MSWindowsClipboardTests.cpp b/src/test/integtests/platform/MSWindowsClipboardTests.cpp new file mode 100644 index 0000000..f9d09d1 --- /dev/null +++ b/src/test/integtests/platform/MSWindowsClipboardTests.cpp @@ -0,0 +1,229 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "platform/MSWindowsClipboard.h" +#include "platform/IMSWindowsClipboardFacade.h" + +#include "test/global/gmock.h" +#include "test/global/gtest.h" + +class MSWindowsClipboardTests : public ::testing::Test +{ +protected: + virtual void SetUp() + { + emptyClipboard(); + } + + virtual void TearDown() + { + emptyClipboard(); + } + +private: + void emptyClipboard() + { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.empty(); + } +}; + +class MockFacade : public IMSWindowsClipboardFacade +{ +public: + MOCK_METHOD2(write, void(HANDLE, UINT)); +}; + +TEST_F(MSWindowsClipboardTests, emptyUnowned_openCalled_returnsTrue) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + + bool actual = clipboard.emptyUnowned(); + + EXPECT_EQ(true, actual); +} + +TEST_F(MSWindowsClipboardTests, empty_openCalled_returnsTrue) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + + bool actual = clipboard.empty(); + + EXPECT_EQ(true, actual); +} + +TEST_F(MSWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.add(MSWindowsClipboard::kText, "barrier rocks!"); + + clipboard.empty(); + + bool actual = clipboard.has(MSWindowsClipboard::kText); + EXPECT_EQ(false, actual); +} + +TEST_F(MSWindowsClipboardTests, add_newValue_valueWasStored) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + + clipboard.add(IClipboard::kText, "barrier rocks!"); + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("barrier rocks!", actual); +} + +TEST_F(MSWindowsClipboardTests, add_newValue_writeWasCalled) +{ + MockFacade facade; + EXPECT_CALL(facade, write(testing::_, testing::_)); + + MSWindowsClipboard clipboard(NULL); + clipboard.setFacade(facade); + clipboard.open(0); + + clipboard.add(IClipboard::kText, "barrier rocks!"); +} + +TEST_F(MSWindowsClipboardTests, add_replaceValue_valueWasReplaced) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + + clipboard.add(IClipboard::kText, "barrier rocks!"); + clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("maxivista sucks", actual); +} + +TEST_F(MSWindowsClipboardTests, open_timeIsZero_returnsTrue) +{ + MSWindowsClipboard clipboard(NULL); + + bool actual = clipboard.open(0); + + EXPECT_EQ(true, actual); +} + +TEST_F(MSWindowsClipboardTests, open_timeIsOne_returnsTrue) +{ + MSWindowsClipboard clipboard(NULL); + + bool actual = clipboard.open(1); + + EXPECT_EQ(true, actual); +} + +TEST_F(MSWindowsClipboardTests, close_isOpen_noErrors) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + + clipboard.close(); + + // can't assert anything +} + +// looks like this test may fail intermittently: +// * http://buildbot.symless.com:8000/builders/trunk-win32/builds/246/steps/shell_3/logs/stdio +/*TEST_F(MSWindowsClipboardTests, getTime_openWithNoEmpty_returnsOne) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(1); + + MSWindowsClipboard::Time actual = clipboard.getTime(); + + // this behavior is different to that of Clipboard which only + // returns the value passed into open(t) after empty() is called. + EXPECT_EQ(1, actual); +}*/ + +// this also fails intermittently: +// http://buildbot.symless.com:8000/builders/trunk-win32/builds/266/steps/shell_3/logs/stdio +/*TEST_F(MSWindowsClipboardTests, getTime_openAndEmpty_returnsOne) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(1); + clipboard.empty(); + + MSWindowsClipboard::Time actual = clipboard.getTime(); + + EXPECT_EQ(1, actual); +}*/ + +TEST_F(MSWindowsClipboardTests, has_withFormatAdded_returnsTrue) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.empty(); + clipboard.add(IClipboard::kText, "barrier rocks!"); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_EQ(true, actual); +} + +TEST_F(MSWindowsClipboardTests, has_withNoFormats_returnsFalse) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.empty(); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_EQ(false, actual); +} + +TEST_F(MSWindowsClipboardTests, get_withNoFormats_returnsEmpty) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.empty(); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("", actual); +} + +TEST_F(MSWindowsClipboardTests, get_withFormatAdded_returnsExpected) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.empty(); + clipboard.add(IClipboard::kText, "barrier rocks!"); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("barrier rocks!", actual); +} + +TEST_F(MSWindowsClipboardTests, isOwnedByBarrier_defaultState_noError) +{ + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + + bool actual = clipboard.isOwnedByBarrier(); + + EXPECT_EQ(true, actual); +} diff --git a/src/test/integtests/platform/MSWindowsKeyStateTests.cpp b/src/test/integtests/platform/MSWindowsKeyStateTests.cpp new file mode 100644 index 0000000..f3f9e32 --- /dev/null +++ b/src/test/integtests/platform/MSWindowsKeyStateTests.cpp @@ -0,0 +1,144 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define TEST_ENV + +#include "test/mock/barrier/MockEventQueue.h" +#include "test/mock/barrier/MockKeyMap.h" +#include "platform/MSWindowsKeyState.h" +#include "platform/MSWindowsDesks.h" +#include "platform/MSWindowsScreen.h" +#include "platform/MSWindowsScreenSaver.h" +#include "base/TMethodJob.h" + +#include "test/global/gtest.h" +#include "test/global/gmock.h" + +// wParam = flags, HIBYTE(lParam) = virtual key, LOBYTE(lParam) = scan code +#define BARRIER_MSG_FAKE_KEY BARRIER_HOOK_LAST_MSG + 4 + +using ::testing::_; +using ::testing::NiceMock; + +class MSWindowsKeyStateTests : public ::testing::Test +{ +protected: + virtual void SetUp() + { + m_hook.loadLibrary(); + m_screensaver = new MSWindowsScreenSaver(); + } + + virtual void TearDown() + { + delete m_screensaver; + } + + MSWindowsDesks* newDesks(IEventQueue* eventQueue) + { + return new MSWindowsDesks( + true, false, m_screensaver, eventQueue, + new TMethodJob<MSWindowsKeyStateTests>( + this, &MSWindowsKeyStateTests::updateKeysCB), false); + } + + void* getEventTarget() const + { + return const_cast<MSWindowsKeyStateTests*>(this); + } + +private: + void updateKeysCB(void*) { } + IScreenSaver* m_screensaver; + MSWindowsHook m_hook; +}; + +TEST_F(MSWindowsKeyStateTests, disable_eventQueueNotUsed) +{ + NiceMock<MockEventQueue> eventQueue; + MSWindowsDesks* desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); + + EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(0); + + keyState.disable(); + delete desks; +} + +TEST_F(MSWindowsKeyStateTests, testAutoRepeat_noRepeatAndButtonIsZero_resultIsTrue) +{ + NiceMock<MockEventQueue> eventQueue; + MSWindowsDesks* desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); + keyState.setLastDown(1); + + bool actual = keyState.testAutoRepeat(true, false, 1); + + ASSERT_TRUE(actual); + delete desks; +} + +TEST_F(MSWindowsKeyStateTests, testAutoRepeat_pressFalse_lastDownIsZero) +{ + NiceMock<MockEventQueue> eventQueue; + MSWindowsDesks* desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); + keyState.setLastDown(1); + + keyState.testAutoRepeat(false, false, 1); + + ASSERT_EQ(0, keyState.getLastDown()); + delete desks; +} + +TEST_F(MSWindowsKeyStateTests, saveModifiers_noModifiers_savedModifiers0) +{ + NiceMock<MockEventQueue> eventQueue; + MSWindowsDesks* desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); + + keyState.saveModifiers(); + + ASSERT_EQ(0, keyState.getSavedModifiers()); + delete desks; +} + +TEST_F(MSWindowsKeyStateTests, testKoreanLocale_inputModeKey_resultCorrectKeyID) +{ + NiceMock<MockEventQueue> eventQueue; + MSWindowsDesks* desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); + + keyState.setKeyLayout((HKL)0x00000412u); // for ko-KR local ID + ASSERT_EQ(0xEF31, keyState.getKeyID(0x15u, 0x1f2u)); // VK_HANGUL from Hangul key + ASSERT_EQ(0xEF34, keyState.getKeyID(0x19u, 0x1f1u)); // VK_HANJA from Hanja key + ASSERT_EQ(0xEF31, keyState.getKeyID(0x15u, 0x11du)); // VK_HANGUL from R-Alt key + ASSERT_EQ(0xEF34, keyState.getKeyID(0x19u, 0x138u)); // VK_HANJA from R-Ctrl key + + keyState.setKeyLayout((HKL)0x00000411); // for ja-jp locale ID + ASSERT_EQ(0xEF26, keyState.getKeyID(0x15u, 0x1du)); // VK_KANA + ASSERT_EQ(0xEF2A, keyState.getKeyID(0x19u, 0x38u)); // VK_KANJI + + delete desks; +} + diff --git a/src/test/integtests/platform/OSXClipboardTests.cpp b/src/test/integtests/platform/OSXClipboardTests.cpp new file mode 100644 index 0000000..45b73bd --- /dev/null +++ b/src/test/integtests/platform/OSXClipboardTests.cpp @@ -0,0 +1,164 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "platform/OSXClipboard.h" + +#include "test/global/gtest.h" +#include <iostream> + +TEST(OSXClipboardTests, empty_openCalled_returnsTrue) +{ + OSXClipboard clipboard; + clipboard.open(0); + + bool actual = clipboard.empty(); + + EXPECT_EQ(true, actual); +} + +TEST(OSXClipboardTests, empty_singleFormat_hasReturnsFalse) +{ + OSXClipboard clipboard; + clipboard.open(0); + clipboard.add(OSXClipboard::kText, "barrier rocks!"); + + clipboard.empty(); + + bool actual = clipboard.has(OSXClipboard::kText); + EXPECT_EQ(false, actual); +} + +TEST(OSXClipboardTests, add_newValue_valueWasStored) +{ + OSXClipboard clipboard; + clipboard.open(0); + + clipboard.add(IClipboard::kText, "barrier rocks!"); + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("barrier rocks!", actual); +} + +TEST(OSXClipboardTests, add_replaceValue_valueWasReplaced) +{ + OSXClipboard clipboard; + clipboard.open(0); + + clipboard.add(IClipboard::kText, "barrier rocks!"); + clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("maxivista sucks", actual); +} + +TEST(OSXClipboardTests, open_timeIsZero_returnsTrue) +{ + OSXClipboard clipboard; + + bool actual = clipboard.open(0); + + EXPECT_EQ(true, actual); +} + +TEST(OSXClipboardTests, open_timeIsOne_returnsTrue) +{ + OSXClipboard clipboard; + + bool actual = clipboard.open(1); + + EXPECT_EQ(true, actual); +} + +TEST(OSXClipboardTests, close_isOpen_noErrors) +{ + OSXClipboard clipboard; + clipboard.open(0); + + clipboard.close(); + + // can't assert anything +} + +TEST(OSXClipboardTests, getTime_openWithNoEmpty_returnsOne) +{ + OSXClipboard clipboard; + clipboard.open(1); + + OSXClipboard::Time actual = clipboard.getTime(); + + // this behavior is different to that of Clipboard which only + // returns the value passed into open(t) after empty() is called. + EXPECT_EQ((UInt32)1, actual); +} + +TEST(OSXClipboardTests, getTime_openAndEmpty_returnsOne) +{ + OSXClipboard clipboard; + clipboard.open(1); + clipboard.empty(); + + OSXClipboard::Time actual = clipboard.getTime(); + + EXPECT_EQ((UInt32)1, actual); +} + +TEST(OSXClipboardTests, has_withFormatAdded_returnsTrue) +{ + OSXClipboard clipboard; + clipboard.open(0); + clipboard.empty(); + clipboard.add(IClipboard::kText, "barrier rocks!"); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_EQ(true, actual); +} + +TEST(OSXClipboardTests, has_withNoFormats_returnsFalse) +{ + OSXClipboard clipboard; + clipboard.open(0); + clipboard.empty(); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_EQ(false, actual); +} + +TEST(OSXClipboardTests, get_withNoFormats_returnsEmpty) +{ + OSXClipboard clipboard; + clipboard.open(0); + clipboard.empty(); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("", actual); +} + +TEST(OSXClipboardTests, get_withFormatAdded_returnsExpected) +{ + OSXClipboard clipboard; + clipboard.open(0); + clipboard.empty(); + clipboard.add(IClipboard::kText, "barrier rocks!"); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("barrier rocks!", actual); +} diff --git a/src/test/integtests/platform/OSXKeyStateTests.cpp b/src/test/integtests/platform/OSXKeyStateTests.cpp new file mode 100644 index 0000000..4957aaa --- /dev/null +++ b/src/test/integtests/platform/OSXKeyStateTests.cpp @@ -0,0 +1,119 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "test/mock/barrier/MockKeyMap.h" +#include "test/mock/barrier/MockEventQueue.h" +#include "platform/OSXKeyState.h" +#include "base/Log.h" + +#include "test/global/gtest.h" +#include "test/global/gmock.h" + +#define SHIFT_ID_L kKeyShift_L +#define SHIFT_ID_R kKeyShift_R +#define SHIFT_BUTTON 57 +#define A_CHAR_ID 0x00000061 +#define A_CHAR_BUTTON 001 + +class OSXKeyStateTests : public ::testing::Test { +public: + static bool isKeyPressed(const OSXKeyState& keyState, KeyButton button); +}; + +// fakeAndPoll_shift seems to always fail on osx10.6 +#if __MAC_OS_X_VERSION_MIN_REQUIRED > 1060 + +TEST_F(OSXKeyStateTests, fakeAndPoll_shift) +{ + barrier::KeyMap keyMap; + MockEventQueue eventQueue; + OSXKeyState keyState(&eventQueue, keyMap); + keyState.updateKeyMap(); + + keyState.fakeKeyDown(SHIFT_ID_L, 0, 1); + EXPECT_TRUE(isKeyPressed(keyState, SHIFT_BUTTON)); + + keyState.fakeKeyUp(1); + EXPECT_TRUE(!isKeyPressed(keyState, SHIFT_BUTTON)); + + keyState.fakeKeyDown(SHIFT_ID_R, 0, 2); + EXPECT_TRUE(isKeyPressed(keyState, SHIFT_BUTTON)); + + keyState.fakeKeyUp(2); + EXPECT_TRUE(!isKeyPressed(keyState, SHIFT_BUTTON)); +} + +TEST_F(OSXKeyStateTests, fakeAndPoll_charKey) +{ + barrier::KeyMap keyMap; + MockEventQueue eventQueue; + OSXKeyState keyState(&eventQueue, keyMap); + keyState.updateKeyMap(); + + keyState.fakeKeyDown(A_CHAR_ID, 0, 1); + EXPECT_TRUE(isKeyPressed(keyState, A_CHAR_BUTTON)); + + keyState.fakeKeyUp(1); + EXPECT_TRUE(!isKeyPressed(keyState, A_CHAR_BUTTON)); + + // HACK: delete the key in case it was typed into a text editor. + // we should really set focus to an invisible window. + keyState.fakeKeyDown(kKeyBackSpace, 0, 2); + keyState.fakeKeyUp(2); +} + +TEST_F(OSXKeyStateTests, fakeAndPoll_charKeyAndModifier) +{ + barrier::KeyMap keyMap; + MockEventQueue eventQueue; + OSXKeyState keyState(&eventQueue, keyMap); + keyState.updateKeyMap(); + + keyState.fakeKeyDown(A_CHAR_ID, KeyModifierShift, 1); + EXPECT_TRUE(isKeyPressed(keyState, A_CHAR_BUTTON)); + + keyState.fakeKeyUp(1); + EXPECT_TRUE(!isKeyPressed(keyState, A_CHAR_BUTTON)); + + // HACK: delete the key in case it was typed into a text editor. + // we should really set focus to an invisible window. + keyState.fakeKeyDown(kKeyBackSpace, 0, 2); + keyState.fakeKeyUp(2); +} + +bool +OSXKeyStateTests::isKeyPressed(const OSXKeyState& keyState, KeyButton button) +{ + // HACK: allow os to realize key state changes. + ARCH->sleep(.2); + + IKeyState::KeyButtonSet pressed; + keyState.pollPressedKeys(pressed); + + IKeyState::KeyButtonSet::const_iterator it; + for (it = pressed.begin(); it != pressed.end(); ++it) { + LOG((CLOG_DEBUG "checking key %d", *it)); + if (*it == button) { + return true; + } + } + return false; +} + +#endif + diff --git a/src/test/integtests/platform/OSXScreenTests.cpp b/src/test/integtests/platform/OSXScreenTests.cpp new file mode 100644 index 0000000..96beb4d --- /dev/null +++ b/src/test/integtests/platform/OSXScreenTests.cpp @@ -0,0 +1,51 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "platform/OSXScreen.h" +#include "arch/Arch.h" +#include "base/EventQueue.h" + +#include "test/global/gtest.h" + +// disabling these tests - the return value of CGCursorIsVisible is unreliable. +/* +TEST(OSXScreenTests, hideCursor_notPrimary) +{ + EventQueue queue; + OSXScreen screen(true, false); + + screen.hideCursor(); + + EXPECT_EQ(false, CGCursorIsVisible()); + + // workaround for screen class race condition. + ARCH->sleep(.1f); +} + +TEST(OSXScreenTests, showCursor_notPrimary) +{ + EventQueue queue; + OSXScreen screen(false, false); + + screen.showCursor(); + + EXPECT_EQ(true, CGCursorIsVisible()); + + // workaround for screen class race condition. + ARCH->sleep(.1f); +} +*/ diff --git a/src/test/integtests/platform/XWindowsClipboardTests.cpp b/src/test/integtests/platform/XWindowsClipboardTests.cpp new file mode 100644 index 0000000..652ee5e --- /dev/null +++ b/src/test/integtests/platform/XWindowsClipboardTests.cpp @@ -0,0 +1,157 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// TODO: fix tests - compile error on linux +#if 0 + +#include "platform/XWindowsClipboard.h" + +#include "test/global/gtest.h" +#include <iostream> + +class CXWindowsClipboardTests : public ::testing::Test +{ +protected: + virtual void + SetUp() + { + m_display = XOpenDisplay(NULL); + int screen = DefaultScreen(m_display); + Window root = XRootWindow(m_display, screen); + + XSetWindowAttributes attr; + attr.do_not_propagate_mask = 0; + attr.override_redirect = True; + attr.cursor = Cursor(); + + m_window = XCreateWindow( + m_display, root, 0, 0, 1, 1, 0, 0, + InputOnly, CopyFromParent, 0, &attr); + } + + virtual void + TearDown() + { + XDestroyWindow(m_display, m_window); + XCloseDisplay(m_display); + } + + CXWindowsClipboard& + createClipboard() + { + CXWindowsClipboard* clipboard; + clipboard = new CXWindowsClipboard(m_display, m_window, 0); + clipboard->open(0); // needed to empty the clipboard + clipboard->empty(); // needed to own the clipboard + return *clipboard; + } + + Display* m_display; + Window m_window; +}; + +TEST_F(CXWindowsClipboardTests, empty_openCalled_returnsTrue) +{ + CXWindowsClipboard clipboard = createClipboard(); + + bool actual = clipboard.empty(); + + EXPECT_EQ(true, actual); +} + +TEST_F(CXWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) +{ + CXWindowsClipboard clipboard = createClipboard(); + clipboard.add(CXWindowsClipboard::kText, "barrier rocks!"); + + clipboard.empty(); + + bool actual = clipboard.has(CXWindowsClipboard::kText); + EXPECT_FALSE(actual); +} + +TEST_F(CXWindowsClipboardTests, add_newValue_valueWasStored) +{ + CXWindowsClipboard clipboard = createClipboard(); + + clipboard.add(IClipboard::kText, "barrier rocks!"); + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("barrier rocks!", actual); +} + +TEST_F(CXWindowsClipboardTests, add_replaceValue_valueWasReplaced) +{ + CXWindowsClipboard clipboard = createClipboard(); + + clipboard.add(IClipboard::kText, "barrier rocks!"); + clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("maxivista sucks", actual); +} + +TEST_F(CXWindowsClipboardTests, close_isOpen_noErrors) +{ + CXWindowsClipboard clipboard = createClipboard(); + + // clipboard opened in createClipboard() + clipboard.close(); + + // can't assert anything +} + +TEST_F(CXWindowsClipboardTests, has_withFormatAdded_returnsTrue) +{ + CXWindowsClipboard clipboard = createClipboard(); + clipboard.add(IClipboard::kText, "barrier rocks!"); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_EQ(true, actual); +} + +TEST_F(CXWindowsClipboardTests, has_withNoFormats_returnsFalse) +{ + CXWindowsClipboard clipboard = createClipboard(); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_FALSE(actual); +} + +TEST_F(CXWindowsClipboardTests, get_withNoFormats_returnsEmpty) +{ + CXWindowsClipboard clipboard = createClipboard(); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("", actual); +} + +TEST_F(CXWindowsClipboardTests, get_withFormatAdded_returnsExpected) +{ + CXWindowsClipboard clipboard = createClipboard(); + clipboard.add(IClipboard::kText, "barrier rocks!"); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("barrier rocks!", actual); +} + +#endif diff --git a/src/test/integtests/platform/XWindowsKeyStateTests.cpp b/src/test/integtests/platform/XWindowsKeyStateTests.cpp new file mode 100644 index 0000000..ea8ce44 --- /dev/null +++ b/src/test/integtests/platform/XWindowsKeyStateTests.cpp @@ -0,0 +1,246 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define TEST_ENV + +#include "test/mock/barrier/MockKeyMap.h" +#include "test/mock/barrier/MockEventQueue.h" +#include "platform/XWindowsKeyState.h" +#include "base/Log.h" + +#define XK_LATIN1 +#define XK_MISCELLANY +#include <X11/keysymdef.h> + +#if HAVE_XKB_EXTENSION +# include <X11/XKBlib.h> +#endif + +#include "test/global/gtest.h" +#include "test/global/gmock.h" +#include <errno.h> + +class XWindowsKeyStateTests : public ::testing::Test +{ +protected: + XWindowsKeyStateTests() : + m_display(NULL) + { + } + + ~XWindowsKeyStateTests() + { + if (m_display != NULL) { + LOG((CLOG_DEBUG "closing display")); + XCloseDisplay(m_display); + } + } + + virtual void + SetUp() + { + // open the display only once for the entire test suite + if (this->m_display == NULL) { + LOG((CLOG_DEBUG "opening display")); + this->m_display = XOpenDisplay(NULL); + + ASSERT_TRUE(this->m_display != NULL) + << "unable to open display: " << errno; + } + } + + virtual void + TearDown() + { + } + + Display* m_display; +}; + +TEST_F(XWindowsKeyStateTests, setActiveGroup_pollAndSet_groupIsZero) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + keyState.setActiveGroup(XWindowsKeyState::kGroupPollAndSet); + + ASSERT_EQ(0, keyState.group()); +} + +TEST_F(XWindowsKeyStateTests, setActiveGroup_poll_groupIsNotSet) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + keyState.setActiveGroup(XWindowsKeyState::kGroupPoll); + + ASSERT_LE(-1, keyState.group()); +} + +TEST_F(XWindowsKeyStateTests, setActiveGroup_customGroup_groupWasSet) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + keyState.setActiveGroup(1); + + ASSERT_EQ(1, keyState.group()); +} + +TEST_F(XWindowsKeyStateTests, mapModifiersFromX_zeroState_zeroMask) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + int mask = keyState.mapModifiersFromX(0); + + ASSERT_EQ(0, mask); +} + +TEST_F(XWindowsKeyStateTests, mapModifiersToX_zeroMask_resultIsTrue) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + unsigned int modifiers = 0; + bool result = keyState.mapModifiersToX(0, modifiers); + + ASSERT_TRUE(result); +} + +TEST_F(XWindowsKeyStateTests, fakeCtrlAltDel_default_returnsFalse) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + bool result = keyState.fakeCtrlAltDel(); + + ASSERT_FALSE(result); +} + +TEST_F(XWindowsKeyStateTests, pollActiveModifiers_defaultState_returnsZero) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + KeyModifierMask actual = keyState.pollActiveModifiers(); + + ASSERT_EQ(0, actual); +} + +#if 0 // TODO: fix, causes sigsegv +TEST_F(XWindowsKeyStateTests, pollActiveModifiers_shiftKeyDownThenUp_masksAreCorrect) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + // set mock modifier mapping + std::fill(keyState.modifierFromX().begin(), keyState.modifierFromX().end(), 0); + keyState.modifierFromX()[ShiftMapIndex] = KeyModifierShift; + + KeyCode key = XKeysymToKeycode(m_display, XK_Shift_L); + + // fake shift key down (without using barrier) + XTestFakeKeyEvent(m_display, key, true, CurrentTime); + + // function under test (1st call) + KeyModifierMask modDown = keyState.pollActiveModifiers(); + + // fake shift key up (without using barrier) + XTestFakeKeyEvent(m_display, key, false, CurrentTime); + + // function under test (2nd call) + KeyModifierMask modUp = keyState.pollActiveModifiers(); + + EXPECT_TRUE((modDown & KeyModifierShift) == KeyModifierShift) + << "shift key not in mask - key was not pressed"; + + EXPECT_TRUE((modUp & KeyModifierShift) == 0) + << "shift key still in mask - make sure no keys are being held down"; +} +#endif + +TEST_F(XWindowsKeyStateTests, pollActiveGroup_defaultState_returnsZero) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + SInt32 actual = keyState.pollActiveGroup(); + + ASSERT_EQ(0, actual); +} + +TEST_F(XWindowsKeyStateTests, pollActiveGroup_positiveGroup_returnsGroup) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + keyState.group(3); + + SInt32 actual = keyState.pollActiveGroup(); + + ASSERT_EQ(3, actual); +} + +TEST_F(XWindowsKeyStateTests, pollActiveGroup_xkb_areEqual) +{ +#if HAVE_XKB_EXTENSION + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState( + m_display, true, &eventQueue, keyMap); + + // reset the group + keyState.group(-1); + + XkbStateRec state; + + // compare pollActiveGroup() with XkbGetState() + if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) { + SInt32 actual = keyState.pollActiveGroup(); + + ASSERT_EQ(state.group, actual); + } + else { + FAIL() << "XkbGetState() returned error " << errno; + } +#else + SUCCEED() << "Xkb extension not installed"; +#endif +} + diff --git a/src/test/integtests/platform/XWindowsScreenSaverTests.cpp b/src/test/integtests/platform/XWindowsScreenSaverTests.cpp new file mode 100644 index 0000000..c6a2710 --- /dev/null +++ b/src/test/integtests/platform/XWindowsScreenSaverTests.cpp @@ -0,0 +1,48 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// TODO: fix tests +#if 0 + +#include "test/mock/barrier/MockEventQueue.h" +#include "platform/XWindowsScreenSaver.h" + +#include "test/global/gtest.h" +#include <X11/Xlib.h> + +using ::testing::_; + +// TODO: not working on build machine for some reason +TEST(CXWindowsScreenSaverTests, activate_defaultScreen_todo) +{ + Display* display = XOpenDisplay(":0.0"); + Window window = DefaultRootWindow(display); + MockEventQueue eventQueue; + EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); + CXWindowsScreenSaver screenSaver( + display, window, NULL, &eventQueue); + + screenSaver.activate(); + + bool isActive = screenSaver.isActive(); + + screenSaver.deactivate(); + + ASSERT_EQ(true, isActive); +} +#endif diff --git a/src/test/integtests/platform/XWindowsScreenTests.cpp b/src/test/integtests/platform/XWindowsScreenTests.cpp new file mode 100644 index 0000000..b74599c --- /dev/null +++ b/src/test/integtests/platform/XWindowsScreenTests.cpp @@ -0,0 +1,41 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "test/mock/barrier/MockEventQueue.h" +#include "platform/XWindowsScreen.h" + +#include "test/global/gtest.h" + +using ::testing::_; + +TEST(CXWindowsScreenTests, fakeMouseMove_nonPrimary_getCursorPosValuesCorrect) +{ + MockEventQueue eventQueue; + EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2); + EXPECT_CALL(eventQueue, adoptBuffer(_)).Times(2); + EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); + XWindowsScreen screen( + ":0.0", false, false, 0, &eventQueue); + + screen.fakeMouseMove(10, 20); + + int x, y; + screen.getCursorPos(x, y); + ASSERT_EQ(10, x); + ASSERT_EQ(20, y); +} diff --git a/src/test/mock/barrier/MockApp.h b/src/test/mock/barrier/MockApp.h new file mode 100644 index 0000000..91745d3 --- /dev/null +++ b/src/test/mock/barrier/MockApp.h @@ -0,0 +1,44 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#define TEST_ENV + +#include "barrier/App.h" + +#include "test/global/gmock.h" + +class MockApp : public App +{ +public: + MockApp() : App(NULL, NULL, NULL) { } + + MOCK_METHOD0(help, void()); + MOCK_METHOD0(loadConfig, void()); + MOCK_METHOD1(loadConfig, bool(const String&)); + MOCK_CONST_METHOD0(daemonInfo, const char*()); + MOCK_CONST_METHOD0(daemonName, const char*()); + MOCK_METHOD2(parseArgs, void(int, const char* const*)); + MOCK_METHOD0(version, void()); + MOCK_METHOD2(standardStartup, int(int, char**)); + MOCK_METHOD4(runInner, int(int, char**, ILogOutputter*, StartupFunc)); + MOCK_METHOD0(startNode, void()); + MOCK_METHOD0(mainLoop, int()); + MOCK_METHOD2(foregroundStartup, int(int, char**)); + MOCK_METHOD0(createScreen, barrier::Screen*()); +}; diff --git a/src/test/mock/barrier/MockArgParser.h b/src/test/mock/barrier/MockArgParser.h new file mode 100644 index 0000000..b1dc07c --- /dev/null +++ b/src/test/mock/barrier/MockArgParser.h @@ -0,0 +1,33 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#define TEST_ENV + +#include "barrier/ArgParser.h" + +#include "test/global/gmock.h" + +class MockArgParser : public ArgParser +{ +public: + MockArgParser() : ArgParser(NULL) { } + + MOCK_METHOD3(parseGenericArgs, bool(int, const char* const*, int&)); + MOCK_METHOD0(checkUnexpectedArgs, bool()); +}; diff --git a/src/test/mock/barrier/MockEventQueue.h b/src/test/mock/barrier/MockEventQueue.h new file mode 100644 index 0000000..f273736 --- /dev/null +++ b/src/test/mock/barrier/MockEventQueue.h @@ -0,0 +1,67 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "base/IEventQueue.h" + +#include "test/global/gmock.h" + +class MockEventQueue : public IEventQueue +{ +public: + MOCK_METHOD0(loop, void()); + MOCK_METHOD2(newOneShotTimer, EventQueueTimer*(double, void*)); + MOCK_METHOD2(newTimer, EventQueueTimer*(double, void*)); + MOCK_METHOD2(getEvent, bool(Event&, double)); + MOCK_METHOD1(adoptBuffer, void(IEventQueueBuffer*)); + MOCK_METHOD2(registerTypeOnce, Event::Type(Event::Type&, const char*)); + MOCK_METHOD1(removeHandlers, void(void*)); + MOCK_METHOD1(registerType, Event::Type(const char*)); + MOCK_CONST_METHOD0(isEmpty, bool()); + MOCK_METHOD3(adoptHandler, void(Event::Type, void*, IEventJob*)); + MOCK_METHOD1(getTypeName, const char*(Event::Type)); + MOCK_METHOD1(addEvent, void(const Event&)); + MOCK_METHOD2(removeHandler, void(Event::Type, void*)); + MOCK_METHOD1(dispatchEvent, bool(const Event&)); + MOCK_CONST_METHOD2(getHandler, IEventJob*(Event::Type, void*)); + MOCK_METHOD1(deleteTimer, void(EventQueueTimer*)); + MOCK_CONST_METHOD1(getRegisteredType, Event::Type(const String&)); + MOCK_METHOD0(getSystemTarget, void*()); + MOCK_METHOD0(forClient, ClientEvents&()); + MOCK_METHOD0(forIStream, IStreamEvents&()); + MOCK_METHOD0(forIpcClient, IpcClientEvents&()); + MOCK_METHOD0(forIpcClientProxy, IpcClientProxyEvents&()); + MOCK_METHOD0(forIpcServer, IpcServerEvents&()); + MOCK_METHOD0(forIpcServerProxy, IpcServerProxyEvents&()); + MOCK_METHOD0(forIDataSocket, IDataSocketEvents&()); + MOCK_METHOD0(forIListenSocket, IListenSocketEvents&()); + MOCK_METHOD0(forISocket, ISocketEvents&()); + MOCK_METHOD0(forOSXScreen, OSXScreenEvents&()); + MOCK_METHOD0(forClientListener, ClientListenerEvents&()); + MOCK_METHOD0(forClientProxy, ClientProxyEvents&()); + MOCK_METHOD0(forClientProxyUnknown, ClientProxyUnknownEvents&()); + MOCK_METHOD0(forServer, ServerEvents&()); + MOCK_METHOD0(forServerApp, ServerAppEvents&()); + MOCK_METHOD0(forIKeyState, IKeyStateEvents&()); + MOCK_METHOD0(forIPrimaryScreen, IPrimaryScreenEvents&()); + MOCK_METHOD0(forIScreen, IScreenEvents&()); + MOCK_METHOD0(forClipboard, ClipboardEvents&()); + MOCK_METHOD0(forFile, FileEvents&()); + MOCK_CONST_METHOD0(waitForReady, void()); +}; diff --git a/src/test/mock/barrier/MockKeyMap.h b/src/test/mock/barrier/MockKeyMap.h new file mode 100644 index 0000000..ef711a5 --- /dev/null +++ b/src/test/mock/barrier/MockKeyMap.h @@ -0,0 +1,36 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "barrier/KeyMap.h" + +#include "test/global/gmock.h" + +class MockKeyMap : public barrier::KeyMap +{ +public: + MOCK_METHOD1(swap, void(KeyMap&)); + MOCK_METHOD0(finish, void()); + MOCK_METHOD2(foreachKey, void(ForeachKeyCallback, void*)); + MOCK_METHOD1(addHalfDuplexModifier, void(KeyID)); + MOCK_CONST_METHOD2(isHalfDuplex, bool(KeyID, KeyButton)); + MOCK_CONST_METHOD7(mapKey, const KeyMap::KeyItem*( + Keystrokes&, KeyID, SInt32, ModifierToKeys&, KeyModifierMask&, + KeyModifierMask, bool)); +}; diff --git a/src/test/mock/barrier/MockKeyState.h b/src/test/mock/barrier/MockKeyState.h new file mode 100644 index 0000000..308e90a --- /dev/null +++ b/src/test/mock/barrier/MockKeyState.h @@ -0,0 +1,57 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "barrier/KeyState.h" + +#include "test/global/gmock.h" + +class MockKeyMap; +class MockEventQueue; + +// NOTE: do not mock methods that are not pure virtual. this mock exists only +// to provide an implementation of the KeyState abstract class. +class MockKeyState : public KeyState +{ +public: + MockKeyState(const MockEventQueue& eventQueue) : + KeyState((IEventQueue*)&eventQueue) + { + } + + MockKeyState(const MockEventQueue& eventQueue, const MockKeyMap& keyMap) : + KeyState((IEventQueue*)&eventQueue, (barrier::KeyMap&)keyMap) + { + } + + MOCK_CONST_METHOD0(pollActiveGroup, SInt32()); + MOCK_CONST_METHOD0(pollActiveModifiers, KeyModifierMask()); + MOCK_METHOD0(fakeCtrlAltDel, bool()); + MOCK_METHOD1(getKeyMap, void(barrier::KeyMap&)); + MOCK_METHOD1(fakeKey, void(const Keystroke&)); + MOCK_METHOD1(fakeMediaKey, bool(KeyID)); + MOCK_CONST_METHOD1(pollPressedKeys, void(KeyButtonSet&)); +}; + +typedef ::testing::NiceMock<MockKeyState> KeyStateImpl; + +typedef UInt32 KeyID; + +typedef void (*ForeachKeyCallback)( + KeyID, SInt32 group, barrier::KeyMap::KeyItem&, void* userData); diff --git a/src/test/mock/barrier/MockScreen.h b/src/test/mock/barrier/MockScreen.h new file mode 100644 index 0000000..78c195a --- /dev/null +++ b/src/test/mock/barrier/MockScreen.h @@ -0,0 +1,36 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2013-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#define TEST_ENV + +#include "barrier/Screen.h" + +#include "test/global/gmock.h" + +class MockScreen : public barrier::Screen +{ +public: + MockScreen() : barrier::Screen() { } + MOCK_METHOD0(disable, void()); + MOCK_CONST_METHOD4(getShape, void(SInt32&, SInt32&, SInt32&, SInt32&)); + MOCK_CONST_METHOD2(getCursorPos, void(SInt32&, SInt32&)); + MOCK_METHOD0(resetOptions, void()); + MOCK_METHOD1(setOptions, void(const OptionsList&)); + MOCK_METHOD0(enable, void()); +}; diff --git a/src/test/mock/io/MockStream.h b/src/test/mock/io/MockStream.h new file mode 100644 index 0000000..bd12739 --- /dev/null +++ b/src/test/mock/io/MockStream.h @@ -0,0 +1,44 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "io/IStream.h" + +#include "test/global/gmock.h" + +class IEventQueue; + +class MockStream : public barrier::IStream +{ +public: + MockStream() { } + MOCK_METHOD0(close, void()); + MOCK_METHOD2(read, UInt32(void*, UInt32)); + MOCK_METHOD2(write, void(const void*, UInt32)); + MOCK_METHOD0(flush, void()); + MOCK_METHOD0(shutdownInput, void()); + MOCK_METHOD0(shutdownOutput, void()); + MOCK_METHOD0(getInputReadyEvent, Event::Type()); + MOCK_METHOD0(getOutputErrorEvent, Event::Type()); + MOCK_METHOD0(getInputShutdownEvent, Event::Type()); + MOCK_METHOD0(getOutputShutdownEvent, Event::Type()); + MOCK_CONST_METHOD0(getEventTarget, void*()); + MOCK_CONST_METHOD0(isReady, bool()); + MOCK_CONST_METHOD0(getSize, UInt32()); +}; diff --git a/src/test/mock/ipc/MockIpcServer.h b/src/test/mock/ipc/MockIpcServer.h new file mode 100644 index 0000000..4124b41 --- /dev/null +++ b/src/test/mock/ipc/MockIpcServer.h @@ -0,0 +1,68 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2015-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "ipc/IpcServer.h" +#include "ipc/IpcMessage.h" +#include "arch/Arch.h" + +#include "test/global/gmock.h" + +using ::testing::_; +using ::testing::Invoke; + +class IEventQueue; + +class MockIpcServer : public IpcServer +{ +public: + MockIpcServer() : + m_sendCond(ARCH->newCondVar()), + m_sendMutex(ARCH->newMutex()) { } + + ~MockIpcServer() { + if (m_sendCond != NULL) { + ARCH->closeCondVar(m_sendCond); + } + + if (m_sendMutex != NULL) { + ARCH->closeMutex(m_sendMutex); + } + } + + MOCK_METHOD0(listen, void()); + MOCK_METHOD2(send, void(const IpcMessage&, EIpcClientType)); + MOCK_CONST_METHOD1(hasClients, bool(EIpcClientType)); + + void delegateToFake() { + ON_CALL(*this, send(_, _)).WillByDefault(Invoke(this, &MockIpcServer::mockSend)); + } + + void waitForSend() { + ARCH->waitCondVar(m_sendCond, m_sendMutex, 5); + } + +private: + void mockSend(const IpcMessage&, EIpcClientType) { + ArchMutexLock lock(m_sendMutex); + ARCH->broadcastCondVar(m_sendCond); + } + + ArchCond m_sendCond; + ArchMutex m_sendMutex; +}; diff --git a/src/test/mock/server/MockConfig.h b/src/test/mock/server/MockConfig.h new file mode 100644 index 0000000..4161de0 --- /dev/null +++ b/src/test/mock/server/MockConfig.h @@ -0,0 +1,32 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2013-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#define TEST_ENV + +#include "server/Config.h" + +#include "test/global/gmock.h" + +class MockConfig : public Config +{ +public: + MockConfig() : Config() { } + MOCK_METHOD0(getInputFilter, InputFilter*()); + MOCK_CONST_METHOD1(isScreen, bool(const String&)); +}; diff --git a/src/test/mock/server/MockInputFilter.h b/src/test/mock/server/MockInputFilter.h new file mode 100644 index 0000000..edf6de1 --- /dev/null +++ b/src/test/mock/server/MockInputFilter.h @@ -0,0 +1,30 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2013-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#define TEST_ENV + +#include "server/InputFilter.h" + +#include "test/global/gmock.h" + +class MockInputFilter : public InputFilter +{ +public: + MOCK_METHOD1(setPrimaryClient, void(PrimaryClient*)); +}; diff --git a/src/test/mock/server/MockPrimaryClient.h b/src/test/mock/server/MockPrimaryClient.h new file mode 100644 index 0000000..80f18a1 --- /dev/null +++ b/src/test/mock/server/MockPrimaryClient.h @@ -0,0 +1,41 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2013-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#define TEST_ENV + +#include "server/PrimaryClient.h" +#include "base/String.h" + +#include "test/global/gmock.h" + +class MockPrimaryClient : public PrimaryClient +{ +public: + MOCK_CONST_METHOD0(getEventTarget, void*()); + MOCK_CONST_METHOD2(getCursorPos, void(SInt32&, SInt32&)); + MOCK_CONST_METHOD2(setJumpCursorPos, void(SInt32, SInt32)); + MOCK_METHOD1(reconfigure, void(UInt32)); + MOCK_METHOD0(resetOptions, void()); + MOCK_METHOD1(setOptions, void(const OptionsList&)); + MOCK_METHOD0(enable, void()); + MOCK_METHOD0(disable, void()); + MOCK_METHOD2(registerHotKey, UInt32(KeyID, KeyModifierMask)); + MOCK_CONST_METHOD0(getToggleMask, KeyModifierMask()); + MOCK_METHOD1(unregisterHotKey, void(UInt32)); +}; diff --git a/src/test/mock/server/MockServer.h b/src/test/mock/server/MockServer.h new file mode 100644 index 0000000..a45ee08 --- /dev/null +++ b/src/test/mock/server/MockServer.h @@ -0,0 +1,32 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2013-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#define TEST_ENV + +#include "server/Server.h" + +#include "test/global/gmock.h" + +class IEventQueue; + +class MockServer : public Server +{ +public: + MockServer() : Server() { } +}; diff --git a/src/test/unittests/CMakeLists.txt b/src/test/unittests/CMakeLists.txt new file mode 100644 index 0000000..3d21a2b --- /dev/null +++ b/src/test/unittests/CMakeLists.txt @@ -0,0 +1,71 @@ +# barrier -- mouse and keyboard sharing utility +# Copyright (C) 2012-2016 Symless Ltd. +# Copyright (C) 2009 Nick Bolton +# +# This package is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# found in the file LICENSE that should have accompanied this file. +# +# This package is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +file(GLOB_RECURSE headers "*.h") +file(GLOB_RECURSE sources "*.cpp") + +file(GLOB_RECURSE remove_platform "platform/*") +list(REMOVE_ITEM headers ${remove_platform}) +list(REMOVE_ITEM sources ${remove_platform}) + +file(GLOB_RECURSE global_headers "../../test/global/*.h") +file(GLOB_RECURSE global_sources "../../test/global/*.cpp") + +list(APPEND headers ${global_headers}) +list(APPEND sources ${global_sources}) + +file(GLOB_RECURSE mock_headers "../../test/mock/*.h") +file(GLOB_RECURSE mock_sources "../../test/mock/*.cpp") + +list(APPEND headers ${mock_headers}) +list(APPEND sources ${mock_sources}) + +# platform +if (WIN32) + file(GLOB platform_sources "platform/MSWindows*.cpp") + file(GLOB platform_headers "platform/MSWindows*.h") +elseif (APPLE) + file(GLOB platform_sources "platform/OSX*.cpp") + file(GLOB platform_headers "platform/OSX*.h") +elseif (UNIX) + file(GLOB platform_sources "platform/XWindows*.cpp") + file(GLOB platform_headers "platform/XWindows*.h") +endif() + +list(APPEND sources ${platform_headers}) +list(APPEND headers ${platform_sources}) + +include_directories( + ../../ + ../../lib/ + ../../../ext/gtest/include + ../../../ext/gmock/include + ../../../ext +) + +if (UNIX) + include_directories( + ../../.. + ) +endif() + +if (BARRIER_ADD_HEADERS) + list(APPEND sources ${headers}) +endif() + +add_executable(unittests ${sources}) +target_link_libraries(unittests + arch base client server common io net platform server barrier mt ipc gtest gmock ${libs} ${OPENSSL_LIBS}) diff --git a/src/test/unittests/Main.cpp b/src/test/unittests/Main.cpp new file mode 100644 index 0000000..7f0d0fe --- /dev/null +++ b/src/test/unittests/Main.cpp @@ -0,0 +1,50 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "arch/Arch.h" +#include "base/Log.h" + +#if SYSAPI_WIN32 +#include "arch/win32/ArchMiscWindows.h" +#endif + +#include "test/global/gtest.h" + +int +main(int argc, char **argv) +{ +#if SYSAPI_WIN32 + // HACK: shouldn't be needed, but logging fails without this. + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); +#endif + + Arch arch; + arch.init(); + + Log log; + log.setFilter(kDEBUG4); + + testing::InitGoogleTest(&argc, argv); + + // gtest seems to randomly finish with error codes (e.g. -1, -1073741819) + // even when no tests have failed. not sure what causes this, but it + // happens on all platforms and keeps leading to false positives. + // according to the documentation, 1 is a failure, so we should be + // able to trust that code. + return (RUN_ALL_TESTS() == 1) ? 1 : 0; +} diff --git a/src/test/unittests/barrier/ArgParserTests.cpp b/src/test/unittests/barrier/ArgParserTests.cpp new file mode 100644 index 0000000..e14877e --- /dev/null +++ b/src/test/unittests/barrier/ArgParserTests.cpp @@ -0,0 +1,207 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "barrier/ArgParser.h" +#include "barrier/ArgsBase.h" + +#include "test/global/gtest.h" + +TEST(ArgParserTests, isArg_abbreviationsArg_returnTrue) +{ + int i = 1; + const int argc = 2; + const char* argv[argc] = { "stub", "-t" }; + bool result = ArgParser::isArg(i, argc, argv, "-t", NULL); + + EXPECT_EQ(true, result); +} + +TEST(ArgParserTests, isArg_fullArg_returnTrue) +{ + int i = 1; + const int argc = 2; + const char* argv[argc] = { "stub", "--test" }; + bool result = ArgParser::isArg(i, argc, argv, NULL, "--test"); + + EXPECT_EQ(true, result); +} + +TEST(ArgParserTests, isArg_missingArgs_returnFalse) +{ + int i = 1; + const int argc = 2; + const char* argv[argc] = { "stub", "-t" }; + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + bool result = ArgParser::isArg(i, argc, argv, "-t", NULL, 1); + + EXPECT_FALSE(result); + EXPECT_EQ(true, argsBase.m_shouldExit); +} + +TEST(ArgParserTests, searchDoubleQuotes_doubleQuotedArg_returnTrue) +{ + String command("\"stub\""); + size_t left = 0; + size_t right = 0; + + bool result = ArgParser::searchDoubleQuotes(command, left, right); + + EXPECT_EQ(true, result); + EXPECT_EQ(0, left); + EXPECT_EQ(5, right); +} + +TEST(ArgParserTests, searchDoubleQuotes_noDoubleQuotedArg_returnfalse) +{ + String command("stub"); + size_t left = 0; + size_t right = 0; + + bool result = ArgParser::searchDoubleQuotes(command, left, right); + + EXPECT_FALSE(result); + EXPECT_EQ(0, left); + EXPECT_EQ(0, right); +} + +TEST(ArgParserTests, searchDoubleQuotes_oneDoubleQuoteArg_returnfalse) +{ + String command("\"stub"); + size_t left = 0; + size_t right = 0; + + bool result = ArgParser::searchDoubleQuotes(command, left, right); + + EXPECT_FALSE(result); + EXPECT_EQ(0, left); + EXPECT_EQ(0, right); +} + +TEST(ArgParserTests, splitCommandString_oneArg_returnArgv) +{ + String command("stub"); + std::vector<String> argv; + + ArgParser::splitCommandString(command, argv); + + EXPECT_EQ(1, argv.size()); + EXPECT_EQ("stub", argv.at(0)); +} + +TEST(ArgParserTests, splitCommandString_twoArgs_returnArgv) +{ + String command("stub1 stub2"); + std::vector<String> argv; + + ArgParser::splitCommandString(command, argv); + + EXPECT_EQ(2, argv.size()); + EXPECT_EQ("stub1", argv.at(0)); + EXPECT_EQ("stub2", argv.at(1)); +} + +TEST(ArgParserTests, splitCommandString_doubleQuotedArgs_returnArgv) +{ + String command("\"stub1\" stub2 \"stub3\""); + std::vector<String> argv; + + ArgParser::splitCommandString(command, argv); + + EXPECT_EQ(3, argv.size()); + EXPECT_EQ("stub1", argv.at(0)); + EXPECT_EQ("stub2", argv.at(1)); + EXPECT_EQ("stub3", argv.at(2)); +} + +TEST(ArgParserTests, splitCommandString_spaceDoubleQuotedArgs_returnArgv) +{ + String command("\"stub1\" stub2 \"stub3 space\""); + std::vector<String> argv; + + ArgParser::splitCommandString(command, argv); + + EXPECT_EQ(3, argv.size()); + EXPECT_EQ("stub1", argv.at(0)); + EXPECT_EQ("stub2", argv.at(1)); + EXPECT_EQ("stub3 space", argv.at(2)); +} + +TEST(ArgParserTests, getArgv_stringArray_return2DArray) +{ + std::vector<String> argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + argArray.push_back("stub3 space"); + const char** argv = ArgParser::getArgv(argArray); + + String row1(argv[0]); + String row2(argv[1]); + String row3(argv[2]); + + EXPECT_EQ("stub1", row1); + EXPECT_EQ("stub2", row2); + EXPECT_EQ("stub3 space", row3); + + delete[] argv; +} + +TEST(ArgParserTests, assembleCommand_stringArray_returnCommand) +{ + std::vector<String> argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + String command = ArgParser::assembleCommand(argArray); + + EXPECT_EQ("stub1 stub2", command); +} + +TEST(ArgParserTests, assembleCommand_ignoreSecondArg_returnCommand) +{ + std::vector<String> argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + String command = ArgParser::assembleCommand(argArray, "stub2"); + + EXPECT_EQ("stub1", command); +} + +TEST(ArgParserTests, assembleCommand_ignoreSecondArgWithOneParameter_returnCommand) +{ + std::vector<String> argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + argArray.push_back("stub3"); + argArray.push_back("stub4"); + String command = ArgParser::assembleCommand(argArray, "stub2", 1); + + EXPECT_EQ("stub1 stub4", command); +} + +TEST(ArgParserTests, assembleCommand_stringArrayWithSpace_returnCommand) +{ + std::vector<String> argArray; + argArray.push_back("stub1 space"); + argArray.push_back("stub2"); + argArray.push_back("stub3 space"); + String command = ArgParser::assembleCommand(argArray); + + EXPECT_EQ("\"stub1 space\" stub2 \"stub3 space\"", command); +} + diff --git a/src/test/unittests/barrier/ClientArgsParsingTests.cpp b/src/test/unittests/barrier/ClientArgsParsingTests.cpp new file mode 100644 index 0000000..5a1e7d0 --- /dev/null +++ b/src/test/unittests/barrier/ClientArgsParsingTests.cpp @@ -0,0 +1,95 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "barrier/ArgParser.h" +#include "barrier/ClientArgs.h" +#include "test/mock/barrier/MockArgParser.h" + +#include "test/global/gtest.h" + +using ::testing::_; +using ::testing::Invoke; +using ::testing::NiceMock; + +bool +client_stubParseGenericArgs(int, const char* const*, int&) +{ + return false; +} + +bool +client_stubCheckUnexpectedArgs() +{ + return false; +} + +TEST(ClientArgsParsingTests, parseClientArgs_yScrollArg_setYScroll) +{ + NiceMock<MockArgParser> argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + ClientArgs clientArgs; + const int argc = 3; + const char* kYScrollCmd[argc] = { "stub", "--yscroll", "1" }; + + argParser.parseClientArgs(clientArgs, argc, kYScrollCmd); + + EXPECT_EQ(1, clientArgs.m_yscroll); +} + +TEST(ClientArgsParsingTests, parseClientArgs_addressArg_setBarrierAddress) +{ + NiceMock<MockArgParser> argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + ClientArgs clientArgs; + const int argc = 2; + const char* kAddressCmd[argc] = { "stub", "mock_address" }; + + bool result = argParser.parseClientArgs(clientArgs, argc, kAddressCmd); + + EXPECT_EQ("mock_address", clientArgs.m_barrierAddress); + EXPECT_EQ(true, result); +} + +TEST(ClientArgsParsingTests, parseClientArgs_noAddressArg_returnFalse) +{ + NiceMock<MockArgParser> argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + ClientArgs clientArgs; + const int argc = 1; + const char* kNoAddressCmd[argc] = { "stub" }; + + bool result = argParser.parseClientArgs(clientArgs, argc, kNoAddressCmd); + + EXPECT_FALSE(result); +} + +TEST(ClientArgsParsingTests, parseClientArgs_unrecognizedArg_returnFalse) +{ + NiceMock<MockArgParser> argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + ClientArgs clientArgs; + const int argc = 3; + const char* kUnrecognizedCmd[argc] = { "stub", "mock_arg", "mock_address"}; + + bool result = argParser.parseClientArgs(clientArgs, argc, kUnrecognizedCmd); + + EXPECT_FALSE(result); +} diff --git a/src/test/unittests/barrier/ClipboardChunkTests.cpp b/src/test/unittests/barrier/ClipboardChunkTests.cpp new file mode 100644 index 0000000..9dc4a5e --- /dev/null +++ b/src/test/unittests/barrier/ClipboardChunkTests.cpp @@ -0,0 +1,128 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2015-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "barrier/ClipboardChunk.h" +#include "barrier/protocol_types.h" + +#include "test/global/gtest.h" + +TEST(ClipboardChunkTests, start_formatStartChunk) +{ +<<<<<<< HEAD + ClipboardID id = 0; + UInt32 sequence = 0; + String mockDataSize("10"); + ClipboardChunk* chunk = ClipboardChunk::start(id, sequence, mockDataSize); + + EXPECT_EQ(id, chunk->m_chunk[0]); + EXPECT_EQ(sequence, (UInt32)chunk->m_chunk[1]); + EXPECT_EQ(kDataStart, chunk->m_chunk[5]); + EXPECT_EQ('1', chunk->m_chunk[6]); + EXPECT_EQ('0', chunk->m_chunk[7]); + EXPECT_EQ('\0', chunk->m_chunk[8]); +======= + ClipboardID id = 0; + UInt32 sequence = 0; + String mockDataSize("10"); + ClipboardChunk* chunk = ClipboardChunk::start(id, sequence, mockDataSize); + UInt32 temp_m_chunk; + memcpy(&temp_m_chunk, &(chunk->m_chunk[1]), 4); + + EXPECT_EQ(id, chunk->m_chunk[0]); + EXPECT_EQ(sequence, temp_m_chunk); + EXPECT_EQ(kDataStart, chunk->m_chunk[5]); + EXPECT_EQ('1', chunk->m_chunk[6]); + EXPECT_EQ('0', chunk->m_chunk[7]); + EXPECT_EQ('\0', chunk->m_chunk[8]); +>>>>>>> master + + delete chunk; +} + +TEST(ClipboardChunkTests, data_formatDataChunk) +{ +<<<<<<< HEAD + ClipboardID id = 0; + UInt32 sequence = 1; + String mockData("mock data"); + ClipboardChunk* chunk = ClipboardChunk::data(id, sequence, mockData); + + EXPECT_EQ(id, chunk->m_chunk[0]); + EXPECT_EQ(sequence, (UInt32)chunk->m_chunk[1]); + EXPECT_EQ(kDataChunk, chunk->m_chunk[5]); + EXPECT_EQ('m', chunk->m_chunk[6]); + EXPECT_EQ('o', chunk->m_chunk[7]); + EXPECT_EQ('c', chunk->m_chunk[8]); + EXPECT_EQ('k', chunk->m_chunk[9]); + EXPECT_EQ(' ', chunk->m_chunk[10]); + EXPECT_EQ('d', chunk->m_chunk[11]); + EXPECT_EQ('a', chunk->m_chunk[12]); + EXPECT_EQ('t', chunk->m_chunk[13]); + EXPECT_EQ('a', chunk->m_chunk[14]); + EXPECT_EQ('\0', chunk->m_chunk[15]); +======= + ClipboardID id = 0; + UInt32 sequence = 1; + String mockData("mock data"); + ClipboardChunk* chunk = ClipboardChunk::data(id, sequence, mockData); + UInt32 temp_m_chunk; + memcpy(&temp_m_chunk, &(chunk->m_chunk[1]), 4); + + EXPECT_EQ(id, chunk->m_chunk[0]); + EXPECT_EQ(sequence, temp_m_chunk); + EXPECT_EQ(kDataChunk, chunk->m_chunk[5]); + EXPECT_EQ('m', chunk->m_chunk[6]); + EXPECT_EQ('o', chunk->m_chunk[7]); + EXPECT_EQ('c', chunk->m_chunk[8]); + EXPECT_EQ('k', chunk->m_chunk[9]); + EXPECT_EQ(' ', chunk->m_chunk[10]); + EXPECT_EQ('d', chunk->m_chunk[11]); + EXPECT_EQ('a', chunk->m_chunk[12]); + EXPECT_EQ('t', chunk->m_chunk[13]); + EXPECT_EQ('a', chunk->m_chunk[14]); + EXPECT_EQ('\0', chunk->m_chunk[15]); +>>>>>>> master + + delete chunk; +} + +TEST(ClipboardChunkTests, end_formatDataChunk) +{ +<<<<<<< HEAD + ClipboardID id = 1; + UInt32 sequence = 1; + ClipboardChunk* chunk = ClipboardChunk::end(id, sequence); + + EXPECT_EQ(id, chunk->m_chunk[0]); + EXPECT_EQ(sequence, (UInt32)chunk->m_chunk[1]); + EXPECT_EQ(kDataEnd, chunk->m_chunk[5]); + EXPECT_EQ('\0', chunk->m_chunk[6]); +======= + ClipboardID id = 1; + UInt32 sequence = 1; + ClipboardChunk* chunk = ClipboardChunk::end(id, sequence); + UInt32 temp_m_chunk; + memcpy(&temp_m_chunk, &(chunk->m_chunk[1]), 4); + + EXPECT_EQ(id, chunk->m_chunk[0]); + EXPECT_EQ(sequence, temp_m_chunk); + EXPECT_EQ(kDataEnd, chunk->m_chunk[5]); + EXPECT_EQ('\0', chunk->m_chunk[6]); +>>>>>>> master + + delete chunk; +} diff --git a/src/test/unittests/barrier/ClipboardTests.cpp b/src/test/unittests/barrier/ClipboardTests.cpp new file mode 100644 index 0000000..f710751 --- /dev/null +++ b/src/test/unittests/barrier/ClipboardTests.cpp @@ -0,0 +1,404 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "barrier/Clipboard.h" + +#include "test/global/gtest.h" + +TEST(ClipboardTests, empty_openCalled_returnsTrue) +{ + Clipboard clipboard; + clipboard.open(0); + + bool actual = clipboard.empty(); + + EXPECT_EQ(true, actual); +} + +TEST(ClipboardTests, empty_singleFormat_hasReturnsFalse) +{ + Clipboard clipboard; + clipboard.open(0); + clipboard.add(Clipboard::kText, "barrier rocks!"); + + clipboard.empty(); + + bool actual = clipboard.has(Clipboard::kText); + EXPECT_FALSE(actual); +} + +TEST(ClipboardTests, add_newValue_valueWasStored) +{ + Clipboard clipboard; + clipboard.open(0); + + clipboard.add(IClipboard::kText, "barrier rocks!"); + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("barrier rocks!", actual); +} + +TEST(ClipboardTests, add_replaceValue_valueWasReplaced) +{ + Clipboard clipboard; + clipboard.open(0); + + clipboard.add(IClipboard::kText, "barrier rocks!"); + clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("maxivista sucks", actual); +} + +TEST(ClipboardTests, open_timeIsZero_returnsTrue) +{ + Clipboard clipboard; + + bool actual = clipboard.open(0); + + EXPECT_EQ(true, actual); +} + +TEST(ClipboardTests, open_timeIsOne_returnsTrue) +{ + Clipboard clipboard; + + bool actual = clipboard.open(1); + + EXPECT_EQ(true, actual); +} + +TEST(ClipboardTests, close_isOpen_noErrors) +{ + Clipboard clipboard; + clipboard.open(0); + + clipboard.close(); + + // can't assert anything +} + +TEST(ClipboardTests, getTime_openWithNoEmpty_returnsZero) +{ + Clipboard clipboard; + clipboard.open(1); + + Clipboard::Time actual = clipboard.getTime(); + + EXPECT_EQ(0, actual); +} + +TEST(ClipboardTests, getTime_openAndEmpty_returnsOne) +{ + Clipboard clipboard; + clipboard.open(1); + clipboard.empty(); + + Clipboard::Time actual = clipboard.getTime(); + + EXPECT_EQ(1, actual); +} + +TEST(ClipboardTests, has_withFormatAdded_returnsTrue) +{ + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "barrier rocks!"); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_EQ(true, actual); +} + +TEST(ClipboardTests, has_withNoFormats_returnsFalse) +{ + Clipboard clipboard; + clipboard.open(0); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_FALSE(actual); +} + +TEST(ClipboardTests, get_withNoFormats_returnsEmpty) +{ + Clipboard clipboard; + clipboard.open(0); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("", actual); +} + +TEST(ClipboardTests, get_withFormatAdded_returnsExpected) +{ + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "barrier rocks!"); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("barrier rocks!", actual); +} + +TEST(ClipboardTests, marshall_addNotCalled_firstCharIsZero) +{ + Clipboard clipboard; + + String actual = clipboard.marshall(); + + // seems to return "\0\0\0\0" but EXPECT_EQ can't assert this, + // so instead, just assert that first char is '\0'. + EXPECT_EQ(0, (int)actual[0]); +} + +TEST(ClipboardTests, marshall_withTextAdded_typeCharIsText) +{ + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "barrier rocks!"); + clipboard.close(); + + String actual = clipboard.marshall(); + + // string contains other data, but 8th char should be kText. + EXPECT_EQ(IClipboard::kText, (int)actual[7]); +} + +TEST(ClipboardTests, marshall_withTextAdded_lastSizeCharIs14) +{ + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "barrier rocks!"); // 14 chars + clipboard.close(); + + String actual = clipboard.marshall(); + + EXPECT_EQ(14, (int)actual[11]); +} + +// TODO: there's some integer -> char encoding going on here. i find it +// hard to believe that the clipboard is the only thing doing this. maybe +// we should refactor this stuff out of the clipboard. +TEST(ClipboardTests, marshall_withTextSize285_sizeCharsValid) +{ + // 285 chars + String data; + data.append("Barrier is Free and Open Source Software that lets you "); + data.append("easily share your mouse and keyboard between multiple "); + data.append("computers, where each computer has it's own display. No "); + data.append("special hardware is required, all you need is a local area "); + data.append("network. Barrier is supported on Windows, Mac OS X and Linux."); + + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, data); + clipboard.close(); + + String actual = clipboard.marshall(); + + // 4 asserts here, but that's ok because we're really just asserting 1 + // thing. the 32-bit size value is split into 4 chars. if the size is 285 + // (29 more than the 8-bit max size), the last char "rolls over" to 29 + // (this is caused by a bit-wise & on 0xff and 8-bit truncation). each + // char before the last stores a bit-shifted version of the number, each + // 1 more power than the last, which is done by bit-shifting [0] by 24, + // [1] by 16, [2] by 8 ([3] is not bit-shifted). + EXPECT_EQ(0, actual[8]); // 285 >> 24 = 285 / (256^3) = 0 + EXPECT_EQ(0, actual[9]); // 285 >> 16 = 285 / (256^2) = 0 + EXPECT_EQ(1, actual[10]); // 285 >> 8 = 285 / (256^1) = 1(.11328125) + EXPECT_EQ(29, actual[11]); // 285 - 256 = 29 +} + +TEST(ClipboardTests, marshall_withHtmlAdded_typeCharIsHtml) +{ + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kHTML, "html sucks"); + clipboard.close(); + + String actual = clipboard.marshall(); + + // string contains other data, but 8th char should be kHTML. + EXPECT_EQ(IClipboard::kHTML, (int)actual[7]); +} + +TEST(ClipboardTests, marshall_withHtmlAndText_has2Formats) +{ + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "barrier rocks"); + clipboard.add(IClipboard::kHTML, "html sucks"); + clipboard.close(); + + String actual = clipboard.marshall(); + + // the number of formats is stored inside the first 4 chars. + // the writeUInt32 function right-aligns numbers in 4 chars, + // so if you right align 2, it will be "\0\0\0\2" in a string. + // we assert that the char at the 4th index is 2 (the number of + // formats that we've added). + EXPECT_EQ(2, (int)actual[3]); +} + +TEST(ClipboardTests, marshall_withTextAdded_endsWithAdded) +{ + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "barrier rocks!"); + clipboard.close(); + + String actual = clipboard.marshall(); + + // string contains other data, but should end in the string we added. + EXPECT_EQ("barrier rocks!", actual.substr(12)); +} + +TEST(ClipboardTests, unmarshall_emptyData_hasTextIsFalse) +{ + Clipboard clipboard; + + String data; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)0; // 0 formats added + + clipboard.unmarshall(data, 0); + + clipboard.open(0); + bool actual = clipboard.has(IClipboard::kText); + EXPECT_FALSE(actual); +} + +TEST(ClipboardTests, unmarshall_withTextSize285_getTextIsValid) +{ + Clipboard clipboard; + + // 285 chars + String text; + text.append("Barrier is Free and Open Source Software that lets you "); + text.append("easily share your mouse and keyboard between multiple "); + text.append("computers, where each computer has it's own display. No "); + text.append("special hardware is required, all you need is a local area "); + text.append("network. Barrier is supported on Windows, Mac OS X and Linux."); + + String data; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)1; // 1 format added + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kText; + data += (char)0; // 285 >> 24 = 285 / (256^3) = 0 + data += (char)0; // 285 >> 16 = 285 / (256^2) = 0 + data += (char)1; // 285 >> 8 = 285 / (256^1) = 1(.11328125) + data += (char)29; // 285 - 256 = 29 + data += text; + + clipboard.unmarshall(data, 0); + + clipboard.open(0); + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ(text, actual); +} + +TEST(ClipboardTests, unmarshall_withTextAndHtml_getTextIsValid) +{ + Clipboard clipboard; + String data; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)2; // 2 formats added + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kText; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)14; + data += "barrier rocks!"; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kHTML; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)10; + data += "html sucks"; + + clipboard.unmarshall(data, 0); + + clipboard.open(0); + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("barrier rocks!", actual); +} + +TEST(ClipboardTests, unmarshall_withTextAndHtml_getHtmlIsValid) +{ + Clipboard clipboard; + String data; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)2; // 2 formats added + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kText; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)14; + data += "barrier rocks!"; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kHTML; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)10; + data += "html sucks"; + + clipboard.unmarshall(data, 0); + + clipboard.open(0); + String actual = clipboard.get(IClipboard::kHTML); + EXPECT_EQ("html sucks", actual); +} + +TEST(ClipboardTests, copy_withSingleText_clipboardsAreEqual) +{ + Clipboard clipboard1; + clipboard1.open(0); + clipboard1.add(Clipboard::kText, "barrier rocks!"); + clipboard1.close(); + + Clipboard clipboard2; + Clipboard::copy(&clipboard2, &clipboard1); + + clipboard2.open(0); + String actual = clipboard2.get(Clipboard::kText); + EXPECT_EQ("barrier rocks!", actual); +} diff --git a/src/test/unittests/barrier/DeprecatedArgsParsingTests.cpp b/src/test/unittests/barrier/DeprecatedArgsParsingTests.cpp new file mode 100644 index 0000000..2856166 --- /dev/null +++ b/src/test/unittests/barrier/DeprecatedArgsParsingTests.cpp @@ -0,0 +1,50 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2015-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "barrier/ArgParser.h" + +#include "test/global/gtest.h" + +using namespace barrier; + +TEST(DeprecatedArgsParsingTests, parseDeprecatedArgs_cryptoPass_returnTrue) +{ + int i = 1; + const int argc = 3; + const char* kCryptoPassCmd[argc] = { "stub", "--crypto-pass", "mock_pass" }; + + ArgParser argParser(NULL); + + bool result = argParser.parseDeprecatedArgs(argc, kCryptoPassCmd, i); + + EXPECT_EQ(true, result); + EXPECT_EQ(2, i); +} + +TEST(DeprecatedArgsParsingTests, parseDeprecatedArgs_cryptoPass_returnFalse) +{ + int i = 1; + const int argc = 3; + const char* kCryptoPassCmd[argc] = { "stub", "--mock-arg", "mock_value" }; + + ArgParser argParser(NULL); + + bool result = argParser.parseDeprecatedArgs(argc, kCryptoPassCmd, i); + + EXPECT_FALSE(result); + EXPECT_EQ(1, i); +} diff --git a/src/test/unittests/barrier/GenericArgsParsingTests.cpp b/src/test/unittests/barrier/GenericArgsParsingTests.cpp new file mode 100644 index 0000000..f43070b --- /dev/null +++ b/src/test/unittests/barrier/GenericArgsParsingTests.cpp @@ -0,0 +1,315 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "barrier/ArgParser.h" +#include "barrier/ArgsBase.h" +#include "test/mock/barrier/MockApp.h" + +#include "test/global/gtest.h" + +using namespace barrier; +using ::testing::_; +using ::testing::Invoke; +using ::testing::NiceMock; + +bool g_helpShowed = false; +bool g_versionShowed = false; + +void +showMockHelp() +{ + g_helpShowed = true; +} + +void +showMockVersion() +{ + g_versionShowed = true; +} + +TEST(GenericArgsParsingTests, parseGenericArgs_logLevelCmd_setLogLevel) +{ + int i = 1; + const int argc = 3; + const char* kLogLevelCmd[argc] = { "stub", "--debug", "DEBUG" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kLogLevelCmd, i); + + String logFilter(argsBase.m_logFilter); + + EXPECT_EQ("DEBUG", logFilter); + EXPECT_EQ(2, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_logFileCmd_saveLogFilename) +{ + int i = 1; + const int argc = 3; + const char* kLogFileCmd[argc] = { "stub", "--log", "mock_filename" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kLogFileCmd, i); + + String logFile(argsBase.m_logFile); + + EXPECT_EQ("mock_filename", logFile); + EXPECT_EQ(2, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_logFileCmdWithSpace_saveLogFilename) +{ + int i = 1; + const int argc = 3; + const char* kLogFileCmdWithSpace[argc] = { "stub", "--log", "mo ck_filename" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kLogFileCmdWithSpace, i); + + String logFile(argsBase.m_logFile); + + EXPECT_EQ("mo ck_filename", logFile); + EXPECT_EQ(2, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_noDeamonCmd_daemonFalse) +{ + int i = 1; + const int argc = 2; + const char* kNoDeamonCmd[argc] = { "stub", "-f" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNoDeamonCmd, i); + + EXPECT_FALSE(argsBase.m_daemon); + EXPECT_EQ(1, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_deamonCmd_daemonTrue) +{ + int i = 1; + const int argc = 2; + const char* kDeamonCmd[argc] = { "stub", "--daemon" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kDeamonCmd, i); + + EXPECT_EQ(true, argsBase.m_daemon); + EXPECT_EQ(1, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_nameCmd_saveName) +{ + int i = 1; + const int argc = 3; + const char* kNameCmd[argc] = { "stub", "--name", "mock" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNameCmd, i); + + EXPECT_EQ("mock", argsBase.m_name); + EXPECT_EQ(2, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_noRestartCmd_restartFalse) +{ + int i = 1; + const int argc = 2; + const char* kNoRestartCmd[argc] = { "stub", "--no-restart" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNoRestartCmd, i); + + EXPECT_FALSE(argsBase.m_restartable); + EXPECT_EQ(1, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_restartCmd_restartTrue) +{ + int i = 1; + const int argc = 2; + const char* kRestartCmd[argc] = { "stub", "--restart" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kRestartCmd, i); + + EXPECT_EQ(true, argsBase.m_restartable); + EXPECT_EQ(1, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_backendCmd_backendTrue) +{ + int i = 1; + const int argc = 2; + const char* kBackendCmd[argc] = { "stub", "-z" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kBackendCmd, i); + + EXPECT_EQ(true, argsBase.m_backend); + EXPECT_EQ(1, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_noHookCmd_noHookTrue) +{ + int i = 1; + const int argc = 2; + const char* kNoHookCmd[argc] = { "stub", "--no-hooks" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNoHookCmd, i); + + EXPECT_EQ(true, argsBase.m_noHooks); + EXPECT_EQ(1, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_helpCmd_showHelp) +{ + g_helpShowed = false; + int i = 1; + const int argc = 2; + const char* kHelpCmd[argc] = { "stub", "--help" }; + + NiceMock<MockApp> app; + ArgParser argParser(&app); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + ON_CALL(app, help()).WillByDefault(Invoke(showMockHelp)); + + argParser.parseGenericArgs(argc, kHelpCmd, i); + + EXPECT_EQ(true, g_helpShowed); + EXPECT_EQ(1, i); +} + + +TEST(GenericArgsParsingTests, parseGenericArgs_versionCmd_showVersion) +{ + g_versionShowed = false; + int i = 1; + const int argc = 2; + const char* kVersionCmd[argc] = { "stub", "--version" }; + + NiceMock<MockApp> app; + ArgParser argParser(&app); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + ON_CALL(app, version()).WillByDefault(Invoke(showMockVersion)); + + argParser.parseGenericArgs(argc, kVersionCmd, i); + + EXPECT_EQ(true, g_versionShowed); + EXPECT_EQ(1, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_noTrayCmd_disableTrayTrue) +{ + int i = 1; + const int argc = 2; + const char* kNoTrayCmd[argc] = { "stub", "--no-tray" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNoTrayCmd, i); + + EXPECT_EQ(true, argsBase.m_disableTray); + EXPECT_EQ(1, i); +} + +TEST(GenericArgsParsingTests, parseGenericArgs_ipcCmd_enableIpcTrue) +{ + int i = 1; + const int argc = 2; + const char* kIpcCmd[argc] = { "stub", "--ipc" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kIpcCmd, i); + + EXPECT_EQ(true, argsBase.m_enableIpc); + EXPECT_EQ(1, i); +} + +#ifndef WINAPI_XWINDOWS +TEST(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnNonLinux_enableDragDropTrue) +{ + int i = 1; + const int argc = 2; + const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kDragDropCmd, i); + + EXPECT_EQ(true, argsBase.m_enableDragDrop); + EXPECT_EQ(1, i); +} +#endif + +#ifdef WINAPI_XWINDOWS +TEST(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnLinux_enableDragDropFalse) +{ + int i = 1; + const int argc = 2; + const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" }; + + ArgParser argParser(NULL); + ArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kDragDropCmd, i); + + EXPECT_FALSE(argsBase.m_enableDragDrop); + EXPECT_EQ(1, i); +} +#endif diff --git a/src/test/unittests/barrier/KeyMapTests.cpp b/src/test/unittests/barrier/KeyMapTests.cpp new file mode 100644 index 0000000..5980633 --- /dev/null +++ b/src/test/unittests/barrier/KeyMapTests.cpp @@ -0,0 +1,216 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2016 Symless + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "barrier/KeyMap.h" + +#include "test/global/gtest.h" +#include "test/global/gmock.h" + +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::SaveArg; + +namespace barrier { + +TEST(KeyMapTests, findBestKey_requiredDown_matchExactFirstItem) +{ + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList; + KeyMap::KeyItem item; + item.m_required = KeyModifierShift; + item.m_sensitive = KeyModifierShift; + KeyModifierMask currentState = KeyModifierShift; + KeyModifierMask desiredState = KeyModifierShift; + itemList.push_back(item); + entryList.push_back(itemList); + + EXPECT_EQ(0, keyMap.findBestKey(entryList, currentState, desiredState)); +} + +TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactFirstItem) +{ + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList; + KeyMap::KeyItem item; + item.m_required = KeyModifierShift; + item.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyModifierMask currentState = KeyModifierShift; + KeyModifierMask desiredState = KeyModifierShift; + itemList.push_back(item); + entryList.push_back(itemList); + + EXPECT_EQ(0, keyMap.findBestKey(entryList, currentState, desiredState)); +} + +TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactSecondItem) +{ + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList1; + KeyMap::KeyItem item1; + item1.m_required = KeyModifierAlt; + item1.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyMap::KeyItemList itemList2; + KeyMap::KeyItem item2; + item2.m_required = KeyModifierShift; + item2.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyModifierMask currentState = KeyModifierShift; + KeyModifierMask desiredState = KeyModifierShift; + itemList1.push_back(item1); + itemList2.push_back(item2); + entryList.push_back(itemList1); + entryList.push_back(itemList2); + + EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState)); +} + +TEST(KeyMapTests, findBestKey_extraSensitiveDown_matchExactSecondItem) +{ + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList1; + KeyMap::KeyItem item1; + item1.m_required = 0; + item1.m_sensitive = KeyModifierAlt; + KeyMap::KeyItemList itemList2; + KeyMap::KeyItem item2; + item2.m_required = 0; + item2.m_sensitive = KeyModifierShift; + KeyModifierMask currentState = KeyModifierAlt; + KeyModifierMask desiredState = KeyModifierAlt; + itemList1.push_back(item1); + itemList2.push_back(item2); + entryList.push_back(itemList1); + entryList.push_back(itemList2); + + EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState)); +} + +TEST(KeyMapTests, findBestKey_noRequiredDown_matchOneRequiredChangeItem) +{ + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList1; + KeyMap::KeyItem item1; + item1.m_required = KeyModifierShift | KeyModifierAlt; + item1.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyMap::KeyItemList itemList2; + KeyMap::KeyItem item2; + item2.m_required = KeyModifierShift; + item2.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyModifierMask currentState = 0; + KeyModifierMask desiredState = 0; + itemList1.push_back(item1); + itemList2.push_back(item2); + entryList.push_back(itemList1); + entryList.push_back(itemList2); + + EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState)); +} + +TEST(KeyMapTests, findBestKey_onlyOneRequiredDown_matchTwoRequiredChangesItem) +{ + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList1; + KeyMap::KeyItem item1; + item1.m_required = KeyModifierShift | KeyModifierAlt | KeyModifierControl; + item1.m_sensitive = KeyModifierShift | KeyModifierAlt | KeyModifierControl; + KeyMap::KeyItemList itemList2; + KeyMap::KeyItem item2; + item2.m_required = KeyModifierShift| KeyModifierAlt; + item2.m_sensitive = KeyModifierShift | KeyModifierAlt | KeyModifierControl; + KeyModifierMask currentState = 0; + KeyModifierMask desiredState = 0; + itemList1.push_back(item1); + itemList2.push_back(item2); + entryList.push_back(itemList1); + entryList.push_back(itemList2); + + EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState)); +} + +TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch) +{ + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList; + KeyMap::KeyItem item; + item.m_required = 0xffffffff; + item.m_sensitive = 0xffffffff; + KeyModifierMask currentState = 0; + KeyModifierMask desiredState = 0; + itemList.push_back(item); + entryList.push_back(itemList); + + EXPECT_EQ(-1, keyMap.findBestKey(entryList, currentState, desiredState)); +} + +TEST(KeyMapTests, isCommand_shiftMask_returnFalse) +{ + KeyMap keyMap; + KeyModifierMask mask= KeyModifierShift; + + EXPECT_FALSE(keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, isCommand_controlMask_returnTrue) +{ + KeyMap keyMap; + KeyModifierMask mask= KeyModifierControl; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, isCommand_alternateMask_returnTrue) +{ + KeyMap keyMap; + KeyModifierMask mask= KeyModifierAlt; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, isCommand_alternateGraphicMask_returnTrue) +{ + KeyMap keyMap; + KeyModifierMask mask= KeyModifierAltGr; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, isCommand_metaMask_returnTrue) +{ + KeyMap keyMap; + KeyModifierMask mask= KeyModifierMeta; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, isCommand_superMask_returnTrue) +{ + KeyMap keyMap; + KeyModifierMask mask= KeyModifierSuper; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +} diff --git a/src/test/unittests/barrier/KeyStateTests.cpp b/src/test/unittests/barrier/KeyStateTests.cpp new file mode 100644 index 0000000..d4154d8 --- /dev/null +++ b/src/test/unittests/barrier/KeyStateTests.cpp @@ -0,0 +1,488 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "test/mock/barrier/MockKeyState.h" +#include "test/mock/barrier/MockEventQueue.h" +#include "test/mock/barrier/MockKeyMap.h" + +#include "test/global/gtest.h" +#include "test/global/gmock.h" + +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::SaveArg; + +void +stubPollPressedKeys(IKeyState::KeyButtonSet& pressedKeys); + +void +assertMaskIsOne(ForeachKeyCallback cb, void* userData); + +const barrier::KeyMap::KeyItem* +stubMapKey( + barrier::KeyMap::Keystrokes& keys, KeyID id, SInt32 group, + barrier::KeyMap::ModifierToKeys& activeModifiers, + KeyModifierMask& currentState, + KeyModifierMask desiredMask, + bool isAutoRepeat); + +barrier::KeyMap::Keystroke s_stubKeystroke(1, false, false); +barrier::KeyMap::KeyItem s_stubKeyItem; + +TEST(CKeyStateTests, onKey_aKeyDown_keyStateOne) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + keyState.onKey(1, true, KeyModifierAlt); + + EXPECT_EQ(1, keyState.getKeyState(1)); +} + +TEST(KeyStateTests, onKey_aKeyUp_keyStateZero) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + keyState.onKey(1, false, KeyModifierAlt); + + EXPECT_EQ(0, keyState.getKeyState(1)); +} + +TEST(KeyStateTests, onKey_invalidKey_keyStateZero) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + keyState.onKey(0, true, KeyModifierAlt); + + EXPECT_EQ(0, keyState.getKeyState(0)); +} + +TEST(KeyStateTests, sendKeyEvent_halfDuplexAndRepeat_addEventNotCalled) +{ + NiceMock<MockKeyMap> keyMap; + NiceMock<MockEventQueue> eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true)); + + EXPECT_CALL(eventQueue, addEvent(_)).Times(0); + + keyState.sendKeyEvent(NULL, false, true, kKeyCapsLock, 0, 0, 0); +} + +TEST(KeyStateTests, sendKeyEvent_halfDuplex_addEventCalledTwice) +{ + NiceMock<MockKeyMap> keyMap; + NiceMock<MockEventQueue> eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + IKeyStateEvents keyStateEvents; + keyStateEvents.setEvents(&eventQueue); + + ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true)); + ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); + + EXPECT_CALL(eventQueue, addEvent(_)).Times(2); + + keyState.sendKeyEvent(NULL, false, false, kKeyCapsLock, 0, 0, 0); +} + +TEST(KeyStateTests, sendKeyEvent_keyRepeat_addEventCalledOnce) +{ + NiceMock<MockKeyMap> keyMap; + NiceMock<MockEventQueue> eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + IKeyStateEvents keyStateEvents; + keyStateEvents.setEvents(&eventQueue); + + ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); + + EXPECT_CALL(eventQueue, addEvent(_)).Times(1); + + keyState.sendKeyEvent(NULL, false, true, 1, 0, 0, 0); +} + +TEST(KeyStateTests, sendKeyEvent_keyDown_addEventCalledOnce) +{ + NiceMock<MockKeyMap> keyMap; + NiceMock<MockEventQueue> eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + IKeyStateEvents keyStateEvents; + keyStateEvents.setEvents(&eventQueue); + + ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); + + EXPECT_CALL(eventQueue, addEvent(_)).Times(1); + + keyState.sendKeyEvent(NULL, true, false, 1, 0, 0, 0); +} + +TEST(KeyStateTests, sendKeyEvent_keyUp_addEventCalledOnce) +{ + NiceMock<MockKeyMap> keyMap; + NiceMock<MockEventQueue> eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + IKeyStateEvents keyStateEvents; + keyStateEvents.setEvents(&eventQueue); + + ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); + + EXPECT_CALL(eventQueue, addEvent(_)).Times(1); + + keyState.sendKeyEvent(NULL, false, false, 1, 0, 0, 0); +} + +TEST(KeyStateTests, updateKeyMap_mockKeyMap_keyMapGotMock) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + // key map member gets a new key map via swap() + EXPECT_CALL(keyMap, swap(_)); + + keyState.updateKeyMap(); +} + +TEST(KeyStateTests, updateKeyState_pollInsertsSingleKey_keyIsDown) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + ON_CALL(keyState, pollPressedKeys(_)).WillByDefault(Invoke(stubPollPressedKeys)); + + keyState.updateKeyState(); + + bool actual = keyState.isKeyDown(1); + ASSERT_TRUE(actual); +} + +TEST(KeyStateTests, updateKeyState_pollDoesNothing_keyNotSet) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + keyState.updateKeyState(); + + bool actual = keyState.isKeyDown(1); + ASSERT_FALSE(actual); +} + +TEST(KeyStateTests, updateKeyState_activeModifiers_maskSet) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(KeyModifierAlt)); + + keyState.updateKeyState(); + + KeyModifierMask actual = keyState.getActiveModifiers(); + ASSERT_EQ(KeyModifierAlt, actual); +} + +TEST(KeyStateTests, updateKeyState_activeModifiers_maskNotSet) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + keyState.updateKeyState(); + + KeyModifierMask actual = keyState.getActiveModifiers(); + ASSERT_EQ(0, actual); +} + +TEST(KeyStateTests, updateKeyState_activeModifiers_keyMapGotModifers) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(1)); + ON_CALL(keyMap, foreachKey(_, _)).WillByDefault(Invoke(assertMaskIsOne)); + + // key map gets new modifiers via foreachKey() + EXPECT_CALL(keyMap, foreachKey(_, _)); + + keyState.updateKeyState(); +} + +TEST(KeyStateTests, setHalfDuplexMask_capsLock_halfDuplexCapsLockAdded) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyCapsLock)); + + keyState.setHalfDuplexMask(KeyModifierCapsLock); +} + +TEST(KeyStateTests, setHalfDuplexMask_numLock_halfDuplexNumLockAdded) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyNumLock)); + + keyState.setHalfDuplexMask(KeyModifierNumLock); +} + +TEST(KeyStateTests, setHalfDuplexMask_scrollLock_halfDuplexScollLockAdded) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyScrollLock)); + + keyState.setHalfDuplexMask(KeyModifierScrollLock); +} + +TEST(KeyStateTests, fakeKeyDown_serverKeyAlreadyDown_fakeKeyCalledTwice) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + s_stubKeyItem.m_client = 0; + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); + + // 2 calls to fakeKeyDown should still call fakeKey, even though + // repeated keys are handled differently. + EXPECT_CALL(keyState, fakeKey(_)).Times(2); + + // call twice to simulate server key already down (a misreported autorepeat). + keyState.fakeKeyDown(1, 0, 0); + keyState.fakeKeyDown(1, 0, 0); +} + +TEST(KeyStateTests, fakeKeyDown_isIgnoredKey_fakeKeyNotCalled) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + EXPECT_CALL(keyState, fakeKey(_)).Times(0); + + keyState.fakeKeyDown(kKeyCapsLock, 0, 0); +} + +TEST(KeyStateTests, fakeKeyDown_mapReturnsKeystrokes_fakeKeyCalled) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + s_stubKeyItem.m_button = 0; + s_stubKeyItem.m_client = 0; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); + + EXPECT_CALL(keyState, fakeKey(_)).Times(1); + + keyState.fakeKeyDown(1, 0, 0); +} + +TEST(KeyStateTests, fakeKeyRepeat_invalidKey_returnsFalse) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + bool actual = keyState.fakeKeyRepeat(0, 0, 0, 0); + + ASSERT_FALSE(actual); +} + +TEST(KeyStateTests, fakeKeyRepeat_nullKey_returnsFalse) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + // set the key to down (we need to make mapKey return a valid key to do this). + barrier::KeyMap::KeyItem keyItem; + keyItem.m_client = 0; + keyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(&keyItem)); + keyState.fakeKeyDown(1, 0, 0); + + // change mapKey to return NULL so that fakeKeyRepeat exits early. + barrier::KeyMap::KeyItem* nullKeyItem = NULL; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(nullKeyItem)); + + bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0); + + ASSERT_FALSE(actual); +} + +TEST(KeyStateTests, fakeKeyRepeat_invalidButton_returnsFalse) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + // set the key to down (we need to make mapKey return a valid key to do this). + barrier::KeyMap::KeyItem keyItem; + keyItem.m_client = 0; + keyItem.m_button = 1; // set to 1 to make fakeKeyDown work. + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(&keyItem)); + keyState.fakeKeyDown(1, 0, 0); + + // change button to 0 so that fakeKeyRepeat will return early. + keyItem.m_button = 0; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(&keyItem)); + + bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0); + + ASSERT_FALSE(actual); +} + +TEST(KeyStateTests, fakeKeyRepeat_validKey_returnsTrue) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + s_stubKeyItem.m_client = 0; + s_stubKeystroke.m_type = barrier::KeyMap::Keystroke::kButton; + s_stubKeystroke.m_data.m_button.m_button = 2; + + // set the button to 1 for fakeKeyDown call + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); + keyState.fakeKeyDown(1, 0, 0); + + // change the button to 2 + s_stubKeyItem.m_button = 2; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); + + bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0); + + ASSERT_TRUE(actual); +} + +TEST(KeyStateTests, fakeKeyUp_buttonNotDown_returnsFalse) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + bool actual = keyState.fakeKeyUp(0); + + ASSERT_FALSE(actual); +} + +TEST(KeyStateTests, fakeKeyUp_buttonAlreadyDown_returnsTrue) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + // press alt down so we get full coverage. + ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(KeyModifierAlt)); + keyState.updateKeyState(); + + // press button 1 down. + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); + keyState.fakeKeyDown(1, 0, 1); + + // this takes the button id, which is the 3rd arg of fakeKeyDown + bool actual = keyState.fakeKeyUp(1); + + ASSERT_TRUE(actual); +} + +TEST(KeyStateTests, fakeAllKeysUp_keysWereDown_keysAreUp) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + // press button 1 down. + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); + keyState.fakeKeyDown(1, 0, 1); + + // method under test + keyState.fakeAllKeysUp(); + + bool actual = keyState.isKeyDown(1); + ASSERT_FALSE(actual); +} + +TEST(KeyStateTests, isKeyDown_keyDown_returnsTrue) +{ + NiceMock<MockKeyMap> keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + // press button 1 down. + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); + keyState.fakeKeyDown(1, 0, 1); + + // method under test + bool actual = keyState.isKeyDown(1); + + ASSERT_TRUE(actual); +} + +TEST(KeyStateTests, isKeyDown_noKeysDown_returnsFalse) +{ + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + + // method under test + bool actual = keyState.isKeyDown(1); + + ASSERT_FALSE(actual); +} + +void +stubPollPressedKeys(IKeyState::KeyButtonSet& pressedKeys) +{ + pressedKeys.insert(1); +} + +void +assertMaskIsOne(ForeachKeyCallback cb, void* userData) +{ + ASSERT_EQ(1, ((KeyState::AddActiveModifierContext*)userData)->m_mask); +} + +const barrier::KeyMap::KeyItem* +stubMapKey( + barrier::KeyMap::Keystrokes& keys, KeyID id, SInt32 group, + barrier::KeyMap::ModifierToKeys& activeModifiers, + KeyModifierMask& currentState, + KeyModifierMask desiredMask, + bool isAutoRepeat) +{ + keys.push_back(s_stubKeystroke); + return &s_stubKeyItem; +} diff --git a/src/test/unittests/barrier/ServerArgsParsingTests.cpp b/src/test/unittests/barrier/ServerArgsParsingTests.cpp new file mode 100644 index 0000000..ed5ed85 --- /dev/null +++ b/src/test/unittests/barrier/ServerArgsParsingTests.cpp @@ -0,0 +1,66 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "barrier/ArgParser.h" +#include "barrier/ServerArgs.h" +#include "test/mock/barrier/MockArgParser.h" + +#include "test/global/gtest.h" + +using ::testing::_; +using ::testing::Invoke; +using ::testing::NiceMock; + +bool +server_stubParseGenericArgs(int, const char* const*, int&) +{ + return false; +} + +bool +server_stubCheckUnexpectedArgs() +{ + return false; +} + +TEST(ServerArgsParsingTests, parseServerArgs_addressArg_setBarrierAddress) +{ + NiceMock<MockArgParser> argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); + ServerArgs serverArgs; + const int argc = 3; + const char* kAddressCmd[argc] = { "stub", "--address", "mock_address" }; + + argParser.parseServerArgs(serverArgs, argc, kAddressCmd); + + EXPECT_EQ("mock_address", serverArgs.m_barrierAddress); +} + +TEST(ServerArgsParsingTests, parseServerArgs_configArg_setConfigFile) +{ + NiceMock<MockArgParser> argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); + ServerArgs serverArgs; + const int argc = 3; + const char* kConfigCmd[argc] = { "stub", "--config", "mock_configFile" }; + + argParser.parseServerArgs(serverArgs, argc, kConfigCmd); + + EXPECT_EQ("mock_configFile", serverArgs.m_configFile); +} diff --git a/src/test/unittests/base/StringTests.cpp b/src/test/unittests/base/StringTests.cpp new file mode 100644 index 0000000..39ad6e8 --- /dev/null +++ b/src/test/unittests/base/StringTests.cpp @@ -0,0 +1,177 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2014-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "base/String.h" + +#include "test/global/gtest.h" + +using namespace barrier; + +TEST(StringTests, format_formatWithArguments_formatedString) +{ + const char* format = "%%%{1}=%{2}"; + const char* arg1 = "answer"; + const char* arg2 = "42"; + + String result = string::format(format, arg1, arg2); + + EXPECT_EQ("%answer=42", result); +} + +TEST(StringTests, findReplaceAll_inputString_replacedString) +{ + String subject = "foobar"; + String find = "bar"; + String replace = "baz"; + + string::findReplaceAll(subject, find, replace); + + EXPECT_EQ("foobaz", subject); +} + +TEST(StringTests, sprintf_formatWithArgument_formatedString) +{ + const char* format = "%s=%d"; + const char* arg1 = "answer"; + int arg2 = 42; + + String result = string::sprintf(format, arg1, arg2); + + EXPECT_EQ("answer=42", result); +} + +TEST(StringTests, toHex_plaintext_hexString) +{ + String subject = "foobar"; + int width = 2; + + string::toHex(subject, width); + + EXPECT_EQ("666f6f626172", subject); +} + +TEST(StringTests, uppercase_lowercaseInput_uppercaseOutput) +{ + String subject = "12foo3BaR"; + + string::uppercase(subject); + + EXPECT_EQ("12FOO3BAR", subject); +} + +TEST(StringTests, removeChar_inputString_removeAllSpecifiedCharactors) +{ + String subject = "foobar"; + const char c = 'o'; + + string::removeChar(subject, c); + + EXPECT_EQ("fbar", subject); +} + +TEST(StringTests, intToString_inputInt_outputString) +{ + size_t value = 123; + + String number = string::sizeTypeToString(value); + + EXPECT_EQ("123", number); +} + +TEST(StringTests, stringToUint_inputString_outputInt) +{ + String number = "123"; + + size_t value = string::stringToSizeType(number); + + EXPECT_EQ(123, value); +} + +TEST(StringTests, splitString_twoSeparator_returnThreeParts) +{ + String string = "stub1:stub2:stub3"; + + std::vector<String> results = string::splitString(string, ':'); + + EXPECT_EQ(3, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); + EXPECT_EQ("stub3", results[2]); +} + +TEST(StringTests, splitString_oneSeparator_returnTwoParts) +{ + String string = "stub1:stub2"; + + std::vector<String> results = string::splitString(string, ':'); + + EXPECT_EQ(2, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); +} + +TEST(StringTests, splitString_noSeparator_returnOriginalString) +{ + String string = "stub1"; + + std::vector<String> results = string::splitString(string, ':'); + + EXPECT_EQ(1, results.size()); + EXPECT_EQ("stub1", results[0]); +} + +TEST(StringTests, splitString_emptyString_returnEmptyVector) +{ + String string; + + std::vector<String> results = string::splitString(string, ':'); + + EXPECT_EQ(0, results.size()); +} + +TEST(StringTests, splitString_tailSeparator_returnTwoParts) +{ + String string = "stub1:stub2:"; + + std::vector<String> results = string::splitString(string, ':'); + + EXPECT_EQ(2, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); +} + +TEST(StringTests, splitString_headSeparator_returnTwoParts) +{ + String string = ":stub1:stub2"; + + std::vector<String> results = string::splitString(string, ':'); + + EXPECT_EQ(2, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); +} + +TEST(StringTests, splitString_headAndTailSeparators_returnTwoParts) +{ + String string = ":stub1:stub2:"; + + std::vector<String> results = string::splitString(string, ':'); + + EXPECT_EQ(2, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); +} diff --git a/src/test/unittests/ipc/IpcLogOutputterTests.cpp b/src/test/unittests/ipc/IpcLogOutputterTests.cpp new file mode 100644 index 0000000..bbfed9c --- /dev/null +++ b/src/test/unittests/ipc/IpcLogOutputterTests.cpp @@ -0,0 +1,165 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2015-2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define TEST_ENV + +#include "test/mock/ipc/MockIpcServer.h" + +#include "mt/Thread.h" +#include "ipc/IpcLogOutputter.h" +#include "base/String.h" +#include "common/common.h" + +#include "test/global/gmock.h" +#include "test/global/gtest.h" + +// HACK: ipc logging only used on windows anyway +#if WINAPI_MSWINDOWS + +using ::testing::_; +using ::testing::Return; +using ::testing::Matcher; +using ::testing::MatcherCast; +using ::testing::Property; +using ::testing::StrEq; +using ::testing::AtLeast; + +using namespace barrier; + +inline const Matcher<const IpcMessage&> IpcLogLineMessageEq(const String& s) { + const Matcher<const IpcLogLineMessage&> m( + Property(&IpcLogLineMessage::logLine, StrEq(s))); + return MatcherCast<const IpcMessage&>(m); +} + +TEST(IpcLogOutputterTests, write_threadingEnabled_bufferIsSent) +{ + MockIpcServer mockServer; + mockServer.delegateToFake(); + + ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); + + EXPECT_CALL(mockServer, hasClients(_)).Times(AtLeast(3)); + EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\n"), _)).Times(1); + EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\n"), _)).Times(1); + + IpcLogOutputter outputter(mockServer, kIpcClientUnknown, true); + outputter.write(kNOTE, "mock 1"); + mockServer.waitForSend(); + outputter.write(kNOTE, "mock 2"); + mockServer.waitForSend(); +} + +TEST(IpcLogOutputterTests, write_overBufferMaxSize_firstLineTruncated) +{ + MockIpcServer mockServer; + + ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); + EXPECT_CALL(mockServer, hasClients(_)).Times(1); + EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"), _)).Times(1); + + IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); + outputter.bufferMaxSize(2); + + // log more lines than the buffer can contain + outputter.write(kNOTE, "mock 1"); + outputter.write(kNOTE, "mock 2"); + outputter.write(kNOTE, "mock 3"); + outputter.sendBuffer(); +} + +TEST(IpcLogOutputterTests, write_underBufferMaxSize_allLinesAreSent) +{ + MockIpcServer mockServer; + + ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); + + EXPECT_CALL(mockServer, hasClients(_)).Times(1); + EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), _)).Times(1); + + IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); + outputter.bufferMaxSize(2); + + // log more lines than the buffer can contain + outputter.write(kNOTE, "mock 1"); + outputter.write(kNOTE, "mock 2"); + outputter.sendBuffer(); +} + +// HACK: temporarily disable this intermittently failing unit test. +// when the build machine is under heavy load, a race condition +// usually happens. +#if 0 +TEST(IpcLogOutputterTests, write_overBufferRateLimit_lastLineTruncated) +{ + MockIpcServer mockServer; + + ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); + + EXPECT_CALL(mockServer, hasClients(_)).Times(2); + EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), _)).Times(1); + EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 4\nmock 5\n"), _)).Times(1); + + IpcLogOutputter outputter(mockServer, false); + outputter.bufferRateLimit(2, 1); // 1s + + // log 1 more line than the buffer can accept in time limit. + outputter.write(kNOTE, "mock 1"); + outputter.write(kNOTE, "mock 2"); + outputter.write(kNOTE, "mock 3"); + + outputter.sendBuffer(); + + // after waiting the time limit send another to make sure + // we can log after the time limit passes. + // HACK: sleep causes the unit test to fail intermittently, + // so lets try 100ms (there must be a better way to solve this) + ARCH->sleep(2); // 2s + outputter.write(kNOTE, "mock 4"); + outputter.write(kNOTE, "mock 5"); + outputter.write(kNOTE, "mock 6"); + + outputter.sendBuffer(); +} +#endif + +TEST(IpcLogOutputterTests, write_underBufferRateLimit_allLinesAreSent) +{ + MockIpcServer mockServer; + + ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); + + EXPECT_CALL(mockServer, hasClients(_)).Times(2); + EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), _)).Times(1); + EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 3\nmock 4\n"), _)).Times(1); + + IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); + outputter.bufferRateLimit(4, 1); // 1s (should be plenty of time) + + // log 1 more line than the buffer can accept in time limit. + outputter.write(kNOTE, "mock 1"); + outputter.write(kNOTE, "mock 2"); + outputter.sendBuffer(); + + // after waiting the time limit send another to make sure + // we can log after the time limit passes. + outputter.write(kNOTE, "mock 3"); + outputter.write(kNOTE, "mock 4"); + outputter.sendBuffer(); +} + +#endif // WINAPI_MSWINDOWS diff --git a/src/test/unittests/platform/OSXKeyStateTests.cpp b/src/test/unittests/platform/OSXKeyStateTests.cpp new file mode 100644 index 0000000..dd9e80f --- /dev/null +++ b/src/test/unittests/platform/OSXKeyStateTests.cpp @@ -0,0 +1,57 @@ +/* + * barrier -- mouse and keyboard sharing utility + * Copyright (C) 2012-2016 Symless Ltd. + * Copyright (C) 2011 Nick Bolton + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "test/mock/barrier/MockKeyMap.h" +#include "test/mock/barrier/MockEventQueue.h" +#include "platform/OSXKeyState.h" + +#include "test/global/gtest.h" +#include "test/global/gmock.h" + +TEST(OSXKeyStateTests, mapModifiersFromOSX_OSXMask_returnBarrierMask) +{ + barrier::KeyMap keyMap; + MockEventQueue eventQueue; + OSXKeyState keyState(&eventQueue, keyMap); + + KeyModifierMask outMask = 0; + + UInt32 shiftMask = 0 | kCGEventFlagMaskShift; + outMask = keyState.mapModifiersFromOSX(shiftMask); + EXPECT_EQ(KeyModifierShift, outMask); + + UInt32 ctrlMask = 0 | kCGEventFlagMaskControl; + outMask = keyState.mapModifiersFromOSX(ctrlMask); + EXPECT_EQ(KeyModifierControl, outMask); + + UInt32 altMask = 0 | kCGEventFlagMaskAlternate; + outMask = keyState.mapModifiersFromOSX(altMask); + EXPECT_EQ(KeyModifierAlt, outMask); + + UInt32 cmdMask = 0 | kCGEventFlagMaskCommand; + outMask = keyState.mapModifiersFromOSX(cmdMask); + EXPECT_EQ(KeyModifierSuper, outMask); + + UInt32 capsMask = 0 | kCGEventFlagMaskAlphaShift; + outMask = keyState.mapModifiersFromOSX(capsMask); + EXPECT_EQ(KeyModifierCapsLock, outMask); + + UInt32 numMask = 0 | kCGEventFlagMaskNumericPad; + outMask = keyState.mapModifiersFromOSX(numMask); + EXPECT_EQ(KeyModifierNumLock, outMask); +} |
