aboutsummaryrefslogtreecommitdiffstats
path: root/src/test
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@ubuntu.com>2018-04-25 18:07:30 -0400
committerLibravatarUnit 193 <unit193@ubuntu.com>2018-04-25 18:07:30 -0400
commit9b1b081cfdb1c0fb6457278775e0823f8bc10f62 (patch)
treece8840148d8445055ba9e4f12263b2208f234c16 /src/test
Import Upstream version 2.0.0+dfsgupstream/2.0.0+dfsg
Diffstat (limited to 'src/test')
-rw-r--r--src/test/CMakeLists.txt33
-rw-r--r--src/test/global/TestEventQueue.cpp53
-rw-r--r--src/test/global/TestEventQueue.h38
-rw-r--r--src/test/global/gmock.h32
-rw-r--r--src/test/global/gtest.h29
-rw-r--r--src/test/guitests/guitests.pro16
-rw-r--r--src/test/guitests/src/VersionCheckerTests.cpp47
-rw-r--r--src/test/guitests/src/VersionCheckerTests.h28
-rw-r--r--src/test/guitests/src/main.cpp26
-rw-r--r--src/test/integtests/CMakeLists.txt71
-rw-r--r--src/test/integtests/Main.cpp108
-rw-r--r--src/test/integtests/arch/ArchInternetTests.cpp37
-rw-r--r--src/test/integtests/ipc/IpcTests.cpp211
-rw-r--r--src/test/integtests/net/NetworkTests.cpp525
-rw-r--r--src/test/integtests/platform/MSWindowsClipboardTests.cpp229
-rw-r--r--src/test/integtests/platform/MSWindowsKeyStateTests.cpp144
-rw-r--r--src/test/integtests/platform/OSXClipboardTests.cpp164
-rw-r--r--src/test/integtests/platform/OSXKeyStateTests.cpp119
-rw-r--r--src/test/integtests/platform/OSXScreenTests.cpp51
-rw-r--r--src/test/integtests/platform/XWindowsClipboardTests.cpp157
-rw-r--r--src/test/integtests/platform/XWindowsKeyStateTests.cpp246
-rw-r--r--src/test/integtests/platform/XWindowsScreenSaverTests.cpp48
-rw-r--r--src/test/integtests/platform/XWindowsScreenTests.cpp41
-rw-r--r--src/test/mock/barrier/MockApp.h44
-rw-r--r--src/test/mock/barrier/MockArgParser.h33
-rw-r--r--src/test/mock/barrier/MockEventQueue.h67
-rw-r--r--src/test/mock/barrier/MockKeyMap.h36
-rw-r--r--src/test/mock/barrier/MockKeyState.h57
-rw-r--r--src/test/mock/barrier/MockScreen.h36
-rw-r--r--src/test/mock/io/MockStream.h44
-rw-r--r--src/test/mock/ipc/MockIpcServer.h68
-rw-r--r--src/test/mock/server/MockConfig.h32
-rw-r--r--src/test/mock/server/MockInputFilter.h30
-rw-r--r--src/test/mock/server/MockPrimaryClient.h41
-rw-r--r--src/test/mock/server/MockServer.h32
-rw-r--r--src/test/unittests/CMakeLists.txt71
-rw-r--r--src/test/unittests/Main.cpp50
-rw-r--r--src/test/unittests/barrier/ArgParserTests.cpp207
-rw-r--r--src/test/unittests/barrier/ClientArgsParsingTests.cpp95
-rw-r--r--src/test/unittests/barrier/ClipboardChunkTests.cpp128
-rw-r--r--src/test/unittests/barrier/ClipboardTests.cpp404
-rw-r--r--src/test/unittests/barrier/DeprecatedArgsParsingTests.cpp50
-rw-r--r--src/test/unittests/barrier/GenericArgsParsingTests.cpp315
-rw-r--r--src/test/unittests/barrier/KeyMapTests.cpp216
-rw-r--r--src/test/unittests/barrier/KeyStateTests.cpp488
-rw-r--r--src/test/unittests/barrier/ServerArgsParsingTests.cpp66
-rw-r--r--src/test/unittests/base/StringTests.cpp177
-rw-r--r--src/test/unittests/ipc/IpcLogOutputterTests.cpp165
-rw-r--r--src/test/unittests/platform/OSXKeyStateTests.cpp57
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);
+}