You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2019/01/07 00:43:37 UTC

[6/7] guacamole-server git commit: GUACAMOLE-662: Migrate tests to test runners generated by new convenience script. Remove unnecessary test runners.

GUACAMOLE-662: Migrate tests to test runners generated by new convenience script. Remove unnecessary test runners.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-server/commit/476b4310
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-server/tree/476b4310
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-server/diff/476b4310

Branch: refs/heads/master
Commit: 476b43104103fb61363f0e451e6553ebac45d157
Parents: 877bf59
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Nov 13 13:26:43 2018 -0800
Committer: Michael Jumper <mj...@apache.org>
Committed: Sat Nov 17 18:06:40 2018 -0800

----------------------------------------------------------------------
 .gitignore                                      |  15 +-
 Makefile.am                                     |   6 +-
 README-unit-testing.md                          |  89 ++++++
 configure.ac                                    |   7 +-
 src/common/.gitignore                           |   9 +
 src/common/Makefile.am                          |   1 +
 src/common/tests/Makefile.am                    |  72 +++++
 src/common/tests/iconv/convert.c                | 185 ++++++++++++
 src/common/tests/rect/clip_and_split.c          | 156 ++++++++++
 src/common/tests/rect/constrain.c               |  43 +++
 src/common/tests/rect/expand_to_grid.c          |  71 +++++
 src/common/tests/rect/extend.c                  |  42 +++
 src/common/tests/rect/init.c                    |  39 +++
 src/common/tests/rect/intersects.c              |  91 ++++++
 src/common/tests/string/count_occurrences.c     |  33 +++
 src/common/tests/string/split.c                 |  63 ++++
 src/libguac/.gitignore                          |  44 +--
 src/libguac/Makefile.am                         |   1 +
 src/libguac/tests/Makefile.am                   |  76 +++++
 src/libguac/tests/client/buffer_pool.c          |  76 +++++
 src/libguac/tests/client/layer_pool.c           |  76 +++++
 src/libguac/tests/parser/append.c               |  77 +++++
 src/libguac/tests/parser/read.c                 | 145 ++++++++++
 src/libguac/tests/pool/next_free.c              |  90 ++++++
 src/libguac/tests/protocol/base64_decode.c      |  55 ++++
 src/libguac/tests/socket/fd_send_instruction.c  | 136 +++++++++
 .../tests/socket/nested_send_instruction.c      | 149 ++++++++++
 src/libguac/tests/unicode/charsize.c            |  33 +++
 src/libguac/tests/unicode/read.c                |  52 ++++
 src/libguac/tests/unicode/strlen.c              |  59 ++++
 src/libguac/tests/unicode/write.c               |  45 +++
 tests/Makefile.am                               |  66 -----
 tests/client/buffer_pool.c                      |  73 -----
 tests/client/client_suite.c                     |  56 ----
 tests/client/client_suite.h                     |  32 --
 tests/client/layer_pool.c                       |  73 -----
 tests/common/common_suite.c                     |  57 ----
 tests/common/common_suite.h                     |  55 ----
 tests/common/guac_iconv.c                       | 128 --------
 tests/common/guac_rect.c                        | 289 -------------------
 tests/common/guac_string.c                      |  70 -----
 tests/protocol/base64_decode.c                  |  59 ----
 tests/protocol/instruction_parse.c              |  76 -----
 tests/protocol/instruction_read.c               | 108 -------
 tests/protocol/instruction_write.c              | 101 -------
 tests/protocol/nest_write.c                     | 109 -------
 tests/protocol/suite.c                          |  59 ----
 tests/protocol/suite.h                          |  43 ---
 tests/test_libguac.c                            |  47 ---
 tests/util/guac_pool.c                          |  89 ------
 tests/util/guac_unicode.c                       |  81 ------
 tests/util/util_suite.c                         |  56 ----
 tests/util/util_suite.h                         |  75 -----
 53 files changed, 1980 insertions(+), 1858 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index dec0cd1..e0a6d53 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,27 +28,16 @@ Makefile
 Makefile.in
 aclocal.m4
 autom4te.cache/
+build-aux/
+libtool
 m4/*
 !README
-compile
-config.guess
 config.h
 config.h.in
 config.log
 config.status
-config.sub
 configure
-depcomp
-install-sh
-libtool
-ltmain.sh
-missing
 stamp-h1
-test-driver
-
-# Test binaries
-tests/test_*
-!tests/test_*.[ch]
 
 # Generated docs
 doc/doxygen-output

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/Makefile.am
----------------------------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
index cbfea85..c75735c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -39,13 +39,11 @@ DIST_SUBDIRS =               \
     src/protocols/rdp        \
     src/protocols/ssh        \
     src/protocols/telnet     \
-    src/protocols/vnc        \
-    tests
+    src/protocols/vnc
 
 SUBDIRS =        \
     src/libguac  \
-    src/common   \
-    tests
+    src/common
 
 if ENABLE_COMMON_SSH
 SUBDIRS += src/common-ssh

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/README-unit-testing.md
----------------------------------------------------------------------
diff --git a/README-unit-testing.md b/README-unit-testing.md
new file mode 100644
index 0000000..5bed872
--- /dev/null
+++ b/README-unit-testing.md
@@ -0,0 +1,89 @@
+
+Unit testing and guacamole-server
+=================================
+
+Unit tests within guacamole-server are implemented using the following:
+
+* automake, which allows arbitrary tests to be declared within `Makefile.am`
+  and uses `make check` to run those tests.
+* CUnit (libcunit), a unit testing framework.
+* `util/generate-test-runner.pl`, a Perl script which generates a test runner
+  written in C which leverages CUnit, running the unit tests declared in each
+  of the given `.c` files. The generated test runner produces output in [TAP
+  format](https://testanything.org/) which is consumed by the TAP test driver
+  provided by automake.
+
+Writing unit tests
+------------------
+
+All unit tests should be within reasonably-isolated C source files, with each
+logical test having its own function of the form:
+
+    void test_SUITENAME__TESTNAME() {
+        ...
+    }
+
+where `TESTNAME` is the arbitrary name of the test and `SUITENAME` is the
+arbitrary name of the test suite that this test belongs to.
+
+**This naming convention is required by `generate-test-runner.pl`.** Absolutely
+all tests MUST follow the above convention if they are to be picked up and
+organized by the test runner generation script. Functions which are not tests
+MUST NOT follow the above convention so that they are _not_ picked up mistakenly
+by the test runner generator as if they were tests.
+
+The `Makefile.am` for a subproject which contains such tests is typically
+modified to contain a sections like the following:
+
+    #
+    # Unit tests for myproj
+    #
+
+    check_PROGRAMS = test_myproj
+    TESTS = $(check_PROGRAMS)
+
+    test_myproj_SOURCES =      \
+        ...all source files...
+
+    test_myproj_CFLAGS =        \
+        -Werror -Wall -pedantic \
+        ...other flags...
+
+    test_myproj_LDADD = \
+        ...libraries...
+
+    #
+    # Autogenerate test runner
+    #
+
+    GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
+    CLEANFILES = _generated_runner.c
+
+    _generated_runner.c: $(test_myproj_SOURCES)
+    	$(AM_V_GEN) $(GEN_RUNNER) $^ > $@
+
+    nodist_test_libguac_SOURCES = \
+        _generated_runner.c
+
+    # Use automake's TAP test driver for running any tests
+    LOG_DRIVER =                \
+        env AM_TAP_AWK='$(AWK)' \
+        $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh
+
+The above declares ...
+
+* ... that a binary, `test_myproj` should be built from the given sources.
+  Note that `test_myproj_SOURCES` contains only the source which was actually
+  written by hand while `nodist_test_myproj_SOURCES` contains only the source
+  which was generated by `generate-test-runner.pl`.
+* ... that this `test_myproj` binary should be run to test this project when
+  `make check` is run, and that automake's TAP driver should be used to
+  consume its output.
+* ... that the `_generated_runner.c` source file is generated dynamically
+  (through running `generate-test-runner.pl` on all non-generated test source)
+  and should not be distributed as part of the source archive.
+
+With tests following the above naming convention in place, and with the
+necessary changes made to the applicable `Makefile.am`, all tests will be
+run automatically when `make check` is run.
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 672d19e..b63ed69 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,6 +19,7 @@
 
 AC_PREREQ([2.61])
 AC_INIT([guacamole-server], [1.0.0])
+AC_CONFIG_AUX_DIR([build-aux])
 AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
 AM_SILENT_RULES([yes])
 
@@ -28,6 +29,9 @@ LT_INIT([dlopen])
 AC_CONFIG_HEADER([config.h])
 AC_CONFIG_MACRO_DIR([m4])
 
+# Use TAP test driver for tests (part of automake)
+AC_REQUIRE_AUX_FILE([tap-driver.sh])
+
 # Programs
 AC_PROG_CC
 AC_PROG_CC_C99
@@ -1299,11 +1303,12 @@ AM_CONDITIONAL([ENABLE_GUACLOG], [test "x${enable_guaclog}"  = "xyes"])
 
 AC_CONFIG_FILES([Makefile
                  doc/Doxyfile
-                 tests/Makefile
                  src/common/Makefile
+                 src/common/tests/Makefile
                  src/common-ssh/Makefile
                  src/terminal/Makefile
                  src/libguac/Makefile
+                 src/libguac/tests/Makefile
                  src/guacd/Makefile
                  src/guacd/man/guacd.8
                  src/guacd/man/guacd.conf.5

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/.gitignore
----------------------------------------------------------------------
diff --git a/src/common/.gitignore b/src/common/.gitignore
new file mode 100644
index 0000000..f7efbda
--- /dev/null
+++ b/src/common/.gitignore
@@ -0,0 +1,9 @@
+
+# Auto-generated test runner and binary
+_generated_runner.c
+test_common
+
+# Test suite output
+*.log
+*.trs
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/Makefile.am
----------------------------------------------------------------------
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 0619010..f98054b 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -27,6 +27,7 @@ AUTOMAKE_OPTIONS = foreign
 ACLOCAL_AMFLAGS = -I m4
 
 noinst_LTLIBRARIES = libguac_common.la
+SUBDIRS = . tests
 
 noinst_HEADERS =            \
     common/io.h             \

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/Makefile.am
----------------------------------------------------------------------
diff --git a/src/common/tests/Makefile.am b/src/common/tests/Makefile.am
new file mode 100644
index 0000000..8169d7d
--- /dev/null
+++ b/src/common/tests/Makefile.am
@@ -0,0 +1,72 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
+# into Makefile.in. Though the build system (GNU Autotools) automatically adds
+# its own license boilerplate to the generated Makefile.in, that boilerplate
+# does not apply to the transcluded portions of Makefile.am which are licensed
+# to you by the ASF under the Apache License, Version 2.0, as described above.
+#
+
+AUTOMAKE_OPTIONS = foreign 
+ACLOCAL_AMFLAGS = -I m4
+
+#
+# Unit tests for libguac_common
+#
+
+check_PROGRAMS = test_common
+TESTS = $(check_PROGRAMS)
+
+test_common_SOURCES =          \
+    iconv/convert.c            \
+    rect/clip_and_split.c      \
+    rect/constrain.c           \
+    rect/expand_to_grid.c      \
+    rect/extend.c              \
+    rect/init.c                \
+    rect/intersects.c          \
+    string/count_occurrences.c \
+    string/split.c
+
+test_common_CFLAGS =        \
+    -Werror -Wall -pedantic \
+    @COMMON_INCLUDE@
+
+test_common_LDADD =  \
+    @COMMON_LTLIB@   \
+    @CUNIT_LIBS@
+
+#
+# Autogenerate test runner
+#
+
+GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
+CLEANFILES = _generated_runner.c
+
+_generated_runner.c: $(test_common_SOURCES)
+	$(AM_V_GEN) $(GEN_RUNNER) $^ > $@
+
+nodist_test_common_SOURCES = \
+    _generated_runner.c
+
+# Use automake's TAP test driver for running any tests
+LOG_DRIVER =                \
+    env AM_TAP_AWK='$(AWK)' \
+    $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/iconv/convert.c
----------------------------------------------------------------------
diff --git a/src/common/tests/iconv/convert.c b/src/common/tests/iconv/convert.c
new file mode 100644
index 0000000..1a00994
--- /dev/null
+++ b/src/common/tests/iconv/convert.c
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "common/iconv.h"
+
+#include <CUnit/CUnit.h>
+
+/**
+ * UTF8 for "papà è bello".
+ */
+unsigned char test_string_utf8[] = {
+    'p',  'a',  'p', 0xC3, 0xA0, ' ',
+    0xC3, 0xA8, ' ',
+    'b',  'e',  'l', 'l',  'o',
+    0x00
+};
+
+/**
+ * UTF16 for "papà è bello".
+ */
+unsigned char test_string_utf16[] = {
+    'p',  0x00, 'a', 0x00, 'p', 0x00, 0xE0, 0x00, ' ', 0x00,
+    0xE8, 0x00, ' ', 0x00,
+    'b',  0x00, 'e', 0x00, 'l', 0x00, 'l',  0x00, 'o', 0x00,
+    0x00, 0x00
+};
+
+/**
+ * ISO-8859-1 for "papà è bello".
+ */
+unsigned char test_string_iso8859_1[] = {
+    'p',  'a',  'p', 0xE0, ' ',
+    0xE8, ' ',
+    'b',  'e',  'l', 'l',  'o',
+    0x00
+};
+
+/**
+ * CP1252 for "papà è bello".
+ */
+unsigned char test_string_cp1252[] = {
+    'p',  'a',  'p', 0xE0, ' ',
+    0xE8, ' ',
+    'b',  'e',  'l', 'l',  'o',
+    0x00
+};
+
+/**
+ * Tests that conversion between character sets using the given guac_iconv_read
+ * and guac_iconv_write implementations matches expectations.
+ *
+ * @param reader
+ *     The guac_iconv_read implementation to use to read the input string.
+ *
+ * @param in_string
+ *     A pointer to the beginning of the input string.
+ *
+ * @param in_length
+ *     The size of the input string in bytes.
+ *
+ * @param writer
+ *     The guac_iconv_write implementation to use to write the output string
+ *     (the converted input string).
+ *
+ * @param out_string
+ *     A pointer to the beginning of a string which contains the expected
+ *     result of the conversion.
+ *
+ * @param out_length
+ *     The size of the expected result in bytes.
+ */
+static void verify_conversion(
+        guac_iconv_read* reader,  unsigned char* in_string,  int in_length,
+        guac_iconv_write* writer, unsigned char* out_string, int out_length) {
+
+    char output[4096];
+    char input[4096];
+
+    const char* current_input = input;
+    char* current_output = output;
+
+    memcpy(input, in_string, in_length);
+    guac_iconv(reader, &current_input,  sizeof(input),
+               writer, &current_output, sizeof(output));
+
+    /* Verify output length */
+    CU_ASSERT_EQUAL(out_length, current_output - output);
+
+    /* Verify entire input read */
+    CU_ASSERT_EQUAL(in_length, current_input - input);
+
+    /* Verify output content */
+    CU_ASSERT_EQUAL(0, memcmp(output, out_string, out_length));
+
+}
+
+/**
+ * Tests which verifies conversion of UTF-8 to itself.
+ */
+void test_iconv__utf8_to_utf8() {
+    verify_conversion(
+            GUAC_READ_UTF8,  test_string_utf8, sizeof(test_string_utf8),
+            GUAC_WRITE_UTF8, test_string_utf8, sizeof(test_string_utf8));
+}
+
+/**
+ * Tests which verifies conversion of UTF-16 to UTF-8.
+ */
+void test_iconv__utf8_to_utf16() {
+    verify_conversion(
+            GUAC_READ_UTF8,   test_string_utf8,  sizeof(test_string_utf8),
+            GUAC_WRITE_UTF16, test_string_utf16, sizeof(test_string_utf16));
+}
+
+/**
+ * Tests which verifies conversion of UTF-16 to itself.
+ */
+void test_iconv__utf16_to_utf16() {
+    verify_conversion(
+            GUAC_READ_UTF16,  test_string_utf16, sizeof(test_string_utf16),
+            GUAC_WRITE_UTF16, test_string_utf16, sizeof(test_string_utf16));
+}
+
+/**
+ * Tests which verifies conversion of UTF-8 to UTF-16.
+ */
+void test_iconv__utf16_to_utf8() {
+    verify_conversion(
+            GUAC_READ_UTF16, test_string_utf16, sizeof(test_string_utf16),
+            GUAC_WRITE_UTF8, test_string_utf8,  sizeof(test_string_utf8));
+}
+
+/**
+ * Tests which verifies conversion of UTF-16 to ISO 8859-1.
+ */
+void test_iconv__utf16_to_iso8859_1() {
+    verify_conversion(
+            GUAC_READ_UTF16,      test_string_utf16,      sizeof(test_string_utf16),
+            GUAC_WRITE_ISO8859_1, test_string_iso8859_1,  sizeof(test_string_iso8859_1));
+}
+
+/**
+ * Tests which verifies conversion of UTF-16 to CP1252.
+ */
+void test_iconv__utf16_to_cp1252() {
+    verify_conversion(
+            GUAC_READ_UTF16,   test_string_utf16,  sizeof(test_string_utf16),
+            GUAC_WRITE_CP1252, test_string_cp1252, sizeof(test_string_cp1252));
+}
+
+/**
+ * Tests which verifies conversion of CP1252 to UTF-8.
+ */
+void test_iconv__cp1252_to_utf8() {
+    verify_conversion(
+            GUAC_READ_CP1252, test_string_cp1252, sizeof(test_string_cp1252),
+            GUAC_WRITE_UTF8,  test_string_utf8,   sizeof(test_string_utf8));
+}
+
+/**
+ * Tests which verifies conversion of ISO 8859-1 to UTF-8.
+ */
+void test_iconv__iso8859_1_to_utf8() {
+    verify_conversion(
+            GUAC_READ_ISO8859_1, test_string_iso8859_1, sizeof(test_string_iso8859_1),
+            GUAC_WRITE_UTF8,     test_string_utf8,      sizeof(test_string_utf8));
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/rect/clip_and_split.c
----------------------------------------------------------------------
diff --git a/src/common/tests/rect/clip_and_split.c b/src/common/tests/rect/clip_and_split.c
new file mode 100644
index 0000000..e286bce
--- /dev/null
+++ b/src/common/tests/rect/clip_and_split.c
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "common/rect.h"
+
+#include <CUnit/CUnit.h>
+
+/**
+ * Test which verifies that guac_common_rect_clip_and_split() divides a
+ * rectangle into subrectangles after removing a "hole" rectangle.
+ */
+void test_rect__clip_and_split() {
+
+    int res;
+
+    guac_common_rect cut;
+    guac_common_rect min;
+    guac_common_rect rect;
+
+    guac_common_rect_init(&min, 10, 10, 10, 10);
+
+    /* Clip top */
+    guac_common_rect_init(&rect, 10, 5, 10, 10);
+    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
+    CU_ASSERT_EQUAL(1, res);
+    CU_ASSERT_EQUAL(10, cut.x);
+    CU_ASSERT_EQUAL(5, cut.y);
+    CU_ASSERT_EQUAL(10, cut.width);
+    CU_ASSERT_EQUAL(5, cut.height);
+
+    CU_ASSERT_EQUAL(10, rect.x);
+    CU_ASSERT_EQUAL(10, rect.y);
+    CU_ASSERT_EQUAL(10, rect.width);
+    CU_ASSERT_EQUAL(5, rect.height);
+
+    /* Clip bottom */
+    guac_common_rect_init(&rect, 10, 15, 10, 10);
+    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
+    CU_ASSERT_EQUAL(1, res);
+    CU_ASSERT_EQUAL(10, cut.x);
+    CU_ASSERT_EQUAL(20, cut.y);
+    CU_ASSERT_EQUAL(10, cut.width);
+    CU_ASSERT_EQUAL(5, cut.height);
+
+    CU_ASSERT_EQUAL(10, rect.x);
+    CU_ASSERT_EQUAL(15, rect.y);
+    CU_ASSERT_EQUAL(10, rect.width);
+    CU_ASSERT_EQUAL(5, rect.height);
+
+    /* Clip left */
+    guac_common_rect_init(&rect, 5, 10, 10, 10);
+    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
+    CU_ASSERT_EQUAL(1, res);
+    CU_ASSERT_EQUAL(5, cut.x);
+    CU_ASSERT_EQUAL(10, cut.y);
+    CU_ASSERT_EQUAL(5, cut.width);
+    CU_ASSERT_EQUAL(10, cut.height);
+
+    CU_ASSERT_EQUAL(10, rect.x);
+    CU_ASSERT_EQUAL(10, rect.y);
+    CU_ASSERT_EQUAL(5, rect.width);
+    CU_ASSERT_EQUAL(10, rect.height);
+
+    /* Clip right */
+    guac_common_rect_init(&rect, 15, 10, 10, 10);
+    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
+    CU_ASSERT_EQUAL(1, res);
+    CU_ASSERT_EQUAL(20, cut.x);
+    CU_ASSERT_EQUAL(10, cut.y);
+    CU_ASSERT_EQUAL(5, cut.width);
+    CU_ASSERT_EQUAL(10, cut.height);
+
+    CU_ASSERT_EQUAL(15, rect.x);
+    CU_ASSERT_EQUAL(10, rect.y);
+    CU_ASSERT_EQUAL(5, rect.width);
+    CU_ASSERT_EQUAL(10, rect.height);
+
+    /*
+     * Test a rectangle which completely covers the hole.
+     * Clip and split until done.
+     */
+    guac_common_rect_init(&rect, 5, 5, 20, 20);
+
+    /* Clip top */
+    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
+    CU_ASSERT_EQUAL(1, res);
+    CU_ASSERT_EQUAL(5, cut.x);
+    CU_ASSERT_EQUAL(5, cut.y);
+    CU_ASSERT_EQUAL(20, cut.width);
+    CU_ASSERT_EQUAL(5, cut.height);
+
+    CU_ASSERT_EQUAL(5, rect.x);
+    CU_ASSERT_EQUAL(10, rect.y);
+    CU_ASSERT_EQUAL(20, rect.width);
+    CU_ASSERT_EQUAL(15, rect.height);
+
+    /* Clip left */
+    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
+    CU_ASSERT_EQUAL(1, res);
+    CU_ASSERT_EQUAL(5, cut.x);
+    CU_ASSERT_EQUAL(10, cut.y);
+    CU_ASSERT_EQUAL(5, cut.width);
+    CU_ASSERT_EQUAL(15, cut.height);
+
+    CU_ASSERT_EQUAL(10, rect.x);
+    CU_ASSERT_EQUAL(10, rect.y);
+    CU_ASSERT_EQUAL(15, rect.width);
+    CU_ASSERT_EQUAL(15, rect.height);
+
+    /* Clip bottom */
+    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
+    CU_ASSERT_EQUAL(1, res);
+    CU_ASSERT_EQUAL(10, cut.x);
+    CU_ASSERT_EQUAL(20, cut.y);
+    CU_ASSERT_EQUAL(15, cut.width);
+    CU_ASSERT_EQUAL(5, cut.height);
+
+    CU_ASSERT_EQUAL(10, rect.x);
+    CU_ASSERT_EQUAL(10, rect.y);
+    CU_ASSERT_EQUAL(15, rect.width);
+    CU_ASSERT_EQUAL(10, rect.height);
+
+    /* Clip right */
+    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
+    CU_ASSERT_EQUAL(20, cut.x);
+    CU_ASSERT_EQUAL(10, cut.y);
+    CU_ASSERT_EQUAL(5, cut.width);
+    CU_ASSERT_EQUAL(10, cut.height);
+
+    CU_ASSERT_EQUAL(10, rect.x);
+    CU_ASSERT_EQUAL(10, rect.y);
+    CU_ASSERT_EQUAL(10, rect.width);
+    CU_ASSERT_EQUAL(10, rect.height);
+
+    /* Make sure nothing is left to do */
+    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
+    CU_ASSERT_EQUAL(0, res);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/rect/constrain.c
----------------------------------------------------------------------
diff --git a/src/common/tests/rect/constrain.c b/src/common/tests/rect/constrain.c
new file mode 100644
index 0000000..793aac2
--- /dev/null
+++ b/src/common/tests/rect/constrain.c
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "common/rect.h"
+
+#include <CUnit/CUnit.h>
+
+/**
+ * Test which verifies that guac_common_rect_constrain() restricts a given
+ * rectangle to arbitrary bounds.
+ */
+void test_rect__constrain() {
+
+    guac_common_rect max;
+    guac_common_rect rect;
+
+    guac_common_rect_init(&rect, -10, -10, 110, 110);
+    guac_common_rect_init(&max, 0, 0, 100, 100);
+    guac_common_rect_constrain(&rect, &max);
+
+    CU_ASSERT_EQUAL(0, rect.x);
+    CU_ASSERT_EQUAL(0, rect.y);
+    CU_ASSERT_EQUAL(100, rect.width);
+    CU_ASSERT_EQUAL(100, rect.height);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/rect/expand_to_grid.c
----------------------------------------------------------------------
diff --git a/src/common/tests/rect/expand_to_grid.c b/src/common/tests/rect/expand_to_grid.c
new file mode 100644
index 0000000..beef87d
--- /dev/null
+++ b/src/common/tests/rect/expand_to_grid.c
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "common/rect.h"
+
+#include <CUnit/CUnit.h>
+
+/**
+ * Test which verifies guac_common_rect_expand_to_grid() properly shifts and
+ * resizes rectangles to fit an NxN grid.
+ */
+void test_rect__expand_to_grid() {
+
+    int cell_size = 16;
+
+    guac_common_rect max;
+    guac_common_rect rect;
+
+    /* Simple adjustment */
+    guac_common_rect_init(&rect, 0, 0, 25, 25);
+    guac_common_rect_init(&max, 0, 0, 100, 100);
+    guac_common_rect_expand_to_grid(cell_size, &rect, &max);
+    CU_ASSERT_EQUAL(0, rect.x);
+    CU_ASSERT_EQUAL(0, rect.y);
+    CU_ASSERT_EQUAL(32, rect.width);
+    CU_ASSERT_EQUAL(32, rect.height);
+
+    /* Adjustment with moving of rect */
+    guac_common_rect_init(&rect, 75, 75, 25, 25);
+    guac_common_rect_init(&max, 0, 0, 100, 100);
+    guac_common_rect_expand_to_grid(cell_size, &rect, &max);
+    CU_ASSERT_EQUAL(max.width - 32, rect.x);
+    CU_ASSERT_EQUAL(max.height - 32, rect.y);
+    CU_ASSERT_EQUAL(32, rect.width);
+    CU_ASSERT_EQUAL(32, rect.height);
+
+    guac_common_rect_init(&rect, -5, -5, 25, 25);
+    guac_common_rect_init(&max, 0, 0, 100, 100);
+    guac_common_rect_expand_to_grid(cell_size, &rect, &max);
+    CU_ASSERT_EQUAL(0, rect.x);
+    CU_ASSERT_EQUAL(0, rect.y);
+    CU_ASSERT_EQUAL(32, rect.width);
+    CU_ASSERT_EQUAL(32, rect.height);
+
+    /* Adjustment with moving and clamping of rect */
+    guac_common_rect_init(&rect, 0, 0, 25, 15);
+    guac_common_rect_init(&max, 0, 5, 32, 15);
+    guac_common_rect_expand_to_grid(cell_size, &rect, &max);
+    CU_ASSERT_EQUAL(max.x, rect.x);
+    CU_ASSERT_EQUAL(max.y, rect.y);
+    CU_ASSERT_EQUAL(max.width, rect.width);
+    CU_ASSERT_EQUAL(max.height, rect.height);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/rect/extend.c
----------------------------------------------------------------------
diff --git a/src/common/tests/rect/extend.c b/src/common/tests/rect/extend.c
new file mode 100644
index 0000000..dc2a0e3
--- /dev/null
+++ b/src/common/tests/rect/extend.c
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "common/rect.h"
+
+#include <CUnit/CUnit.h>
+
+/**
+ * Test which verifies that guac_common_rect_extend() expands the given
+ * rectangle as necessary to contain at least the given bounds.
+ */
+void test_rect__extend() {
+
+    guac_common_rect max;
+    guac_common_rect rect;
+
+    guac_common_rect_init(&rect, 10, 10, 90, 90);
+    guac_common_rect_init(&max, 0, 0, 100, 100);
+    guac_common_rect_extend(&rect, &max);
+    CU_ASSERT_EQUAL(0, rect.x);
+    CU_ASSERT_EQUAL(0, rect.y);
+    CU_ASSERT_EQUAL(100, rect.width);
+    CU_ASSERT_EQUAL(100, rect.height);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/rect/init.c
----------------------------------------------------------------------
diff --git a/src/common/tests/rect/init.c b/src/common/tests/rect/init.c
new file mode 100644
index 0000000..288cd75
--- /dev/null
+++ b/src/common/tests/rect/init.c
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "common/rect.h"
+
+#include <CUnit/CUnit.h>
+
+/**
+ * Test which verifies rectangle initialization via guac_common_rect_init().
+ */
+void test_rect__init() {
+
+    guac_common_rect max;
+
+    guac_common_rect_init(&max, 0, 0, 100, 100);
+
+    CU_ASSERT_EQUAL(0, max.x);
+    CU_ASSERT_EQUAL(0, max.y);
+    CU_ASSERT_EQUAL(100, max.width);
+    CU_ASSERT_EQUAL(100, max.height);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/rect/intersects.c
----------------------------------------------------------------------
diff --git a/src/common/tests/rect/intersects.c b/src/common/tests/rect/intersects.c
new file mode 100644
index 0000000..c480268
--- /dev/null
+++ b/src/common/tests/rect/intersects.c
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "common/rect.h"
+
+#include <CUnit/CUnit.h>
+
+/**
+ * Test which verifies intersection testing via guac_common_rect_intersects().
+ */
+void test_rect__intersects() {
+
+    int res;
+
+    guac_common_rect min;
+    guac_common_rect rect;
+
+    guac_common_rect_init(&min, 10, 10, 10, 10);
+
+    /* Rectangle intersection - empty
+     * rectangle is outside */
+    guac_common_rect_init(&rect, 25, 25, 5, 5);
+    res = guac_common_rect_intersects(&rect, &min);
+    CU_ASSERT_EQUAL(0, res);
+
+    /* Rectangle intersection - complete
+     * rectangle is completely inside */
+    guac_common_rect_init(&rect, 11, 11, 5, 5);
+    res = guac_common_rect_intersects(&rect, &min);
+    CU_ASSERT_EQUAL(2, res);
+
+    /* Rectangle intersection - partial
+     * rectangle intersects UL */
+    guac_common_rect_init(&rect, 8, 8, 5, 5);
+    res = guac_common_rect_intersects(&rect, &min);
+    CU_ASSERT_EQUAL(1, res);
+
+    /* Rectangle intersection - partial
+     * rectangle intersects LR */
+    guac_common_rect_init(&rect, 18, 18, 5, 5);
+    res = guac_common_rect_intersects(&rect, &min);
+    CU_ASSERT_EQUAL(1, res);
+
+    /* Rectangle intersection - complete
+     * rect intersects along UL but inside */
+    guac_common_rect_init(&rect, 10, 10, 5, 5);
+    res = guac_common_rect_intersects(&rect, &min);
+    CU_ASSERT_EQUAL(2, res);
+
+    /* Rectangle intersection - partial
+     * rectangle intersects along L but outside */
+    guac_common_rect_init(&rect, 5, 10, 5, 5);
+    res = guac_common_rect_intersects(&rect, &min);
+    CU_ASSERT_EQUAL(1, res);
+
+    /* Rectangle intersection - complete
+     * rectangle intersects along LR but rest is inside */
+    guac_common_rect_init(&rect, 15, 15, 5, 5);
+    res = guac_common_rect_intersects(&rect, &min);
+    CU_ASSERT_EQUAL(2, res);
+
+    /* Rectangle intersection - partial
+     * rectangle intersects along R but rest is outside */
+    guac_common_rect_init(&rect, 20, 10, 5, 5);
+    res = guac_common_rect_intersects(&rect, &min);
+    CU_ASSERT_EQUAL(1, res);
+
+    /* Rectangle intersection - partial
+     * rectangle encloses min; which is a partial intersection */
+    guac_common_rect_init(&rect, 5, 5, 20, 20);
+    res = guac_common_rect_intersects(&rect, &min);
+    CU_ASSERT_EQUAL(1, res);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/string/count_occurrences.c
----------------------------------------------------------------------
diff --git a/src/common/tests/string/count_occurrences.c b/src/common/tests/string/count_occurrences.c
new file mode 100644
index 0000000..0c7d01d
--- /dev/null
+++ b/src/common/tests/string/count_occurrences.c
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "common/string.h"
+
+#include <CUnit/CUnit.h>
+
+/**
+ * Test which verifies that guac_count_occurrences() counts the number of
+ * occurrences of an arbitrary character within a given string.
+ */
+void test_string__guac_count_occurrences() {
+    CU_ASSERT_EQUAL(4, guac_count_occurrences("this is a test string", 's'));
+    CU_ASSERT_EQUAL(3, guac_count_occurrences("this is a test string", 'i'));
+    CU_ASSERT_EQUAL(0, guac_count_occurrences("", 's'));
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/common/tests/string/split.c
----------------------------------------------------------------------
diff --git a/src/common/tests/string/split.c b/src/common/tests/string/split.c
new file mode 100644
index 0000000..36f8f19
--- /dev/null
+++ b/src/common/tests/string/split.c
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "common/string.h"
+
+#include <CUnit/CUnit.h>
+
+#include <stdlib.h>
+
+/**
+ * Test which verifies that guac_split() splits a string on occurrences of a
+ * given character.
+ */
+void test_string__split() {
+
+    /* Split test string */
+    char** tokens = guac_split("this is a test string", ' ');
+    CU_ASSERT_PTR_NOT_NULL(tokens);
+
+    /* Check resulting tokens */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[0]);
+    CU_ASSERT_STRING_EQUAL("this", tokens[0]);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[1]);
+    CU_ASSERT_STRING_EQUAL("is", tokens[1]);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[2]);
+    CU_ASSERT_STRING_EQUAL("a", tokens[2]);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[3]);
+    CU_ASSERT_STRING_EQUAL("test", tokens[3]);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[4]);
+    CU_ASSERT_STRING_EQUAL("string", tokens[4]);
+
+    CU_ASSERT_PTR_NULL(tokens[5]);
+
+    /* Clean up */
+    free(tokens[0]);
+    free(tokens[1]);
+    free(tokens[2]);
+    free(tokens[3]);
+    free(tokens[4]);
+    free(tokens);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/.gitignore
----------------------------------------------------------------------
diff --git a/src/libguac/.gitignore b/src/libguac/.gitignore
index 95b69b0..ab58079 100644
--- a/src/libguac/.gitignore
+++ b/src/libguac/.gitignore
@@ -1,41 +1,9 @@
 
-# Object code
-*.o
-*.so
-*.lo
-*.la
+# Auto-generated test runner and binary
+_generated_runner.c
+test_libguac
 
-# gcov files
-*.gcda
-*.gcov
-*.gcno
-
-# Backup files
-*~
-
-# Release files
-*.tar.gz
-
-# Files currently being edited by vim or vi
-*.swp
-
-# automake/autoconf
-.deps/
-.libs/
-Makefile
-Makefile.in
-aclocal.m4
-autom4te.cache/
-m4/*
-!README
-config.guess
-config.log
-config.status
-config.sub
-configure
-depcomp
-install-sh
-libtool
-ltmain.sh
-missing
+# Test suite output
+*.log
+*.trs
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/Makefile.am
----------------------------------------------------------------------
diff --git a/src/libguac/Makefile.am b/src/libguac/Makefile.am
index d541df5..2757f70 100644
--- a/src/libguac/Makefile.am
+++ b/src/libguac/Makefile.am
@@ -27,6 +27,7 @@ AUTOMAKE_OPTIONS = foreign
 ACLOCAL_AMFLAGS = -I m4
 
 lib_LTLIBRARIES = libguac.la
+SUBDIRS = . tests
 
 libguacincdir = $(includedir)/guacamole
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/Makefile.am
----------------------------------------------------------------------
diff --git a/src/libguac/tests/Makefile.am b/src/libguac/tests/Makefile.am
new file mode 100644
index 0000000..414a2f4
--- /dev/null
+++ b/src/libguac/tests/Makefile.am
@@ -0,0 +1,76 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
+# into Makefile.in. Though the build system (GNU Autotools) automatically adds
+# its own license boilerplate to the generated Makefile.in, that boilerplate
+# does not apply to the transcluded portions of Makefile.am which are licensed
+# to you by the ASF under the Apache License, Version 2.0, as described above.
+#
+
+AUTOMAKE_OPTIONS = foreign 
+ACLOCAL_AMFLAGS = -I m4
+
+#
+# Unit tests for libguac
+#
+
+check_PROGRAMS = test_libguac
+TESTS = $(check_PROGRAMS)
+
+test_libguac_SOURCES =               \
+    client/buffer_pool.c             \
+    client/layer_pool.c              \
+    parser/append.c                  \
+    parser/read.c                    \
+    pool/next_free.c                 \
+    protocol/base64_decode.c         \
+    socket/fd_send_instruction.c     \
+    socket/nested_send_instruction.c \
+    unicode/charsize.c               \
+    unicode/read.c                   \
+    unicode/strlen.c                 \
+    unicode/write.c
+
+
+test_libguac_CFLAGS =       \
+    -Werror -Wall -pedantic \
+    @LIBGUAC_INCLUDE@
+
+test_libguac_LDADD = \
+    @CUNIT_LIBS@     \
+    @LIBGUAC_LTLIB@
+
+#
+# Autogenerate test runner
+#
+
+GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
+CLEANFILES = _generated_runner.c
+
+_generated_runner.c: $(test_libguac_SOURCES)
+	$(AM_V_GEN) $(GEN_RUNNER) $^ > $@
+
+nodist_test_libguac_SOURCES = \
+    _generated_runner.c
+
+# Use automake's TAP test driver for running any tests
+LOG_DRIVER =                \
+    env AM_TAP_AWK='$(AWK)' \
+    $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/client/buffer_pool.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/client/buffer_pool.c b/src/libguac/tests/client/buffer_pool.c
new file mode 100644
index 0000000..4f3b3c1
--- /dev/null
+++ b/src/libguac/tests/client/buffer_pool.c
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/client.h>
+#include <guacamole/layer.h>
+
+#include <stdbool.h>
+
+/**
+ * Test which verifies that buffers can be allocated and freed using the pool
+ * of buffers available to each guac_client, and that doing so does not disturb
+ * the similar pool of layers.
+ */
+void test_client__buffer_pool() {
+
+    guac_client* client;
+
+    int i;
+    bool seen[GUAC_BUFFER_POOL_INITIAL_SIZE] = { 0 };
+
+    guac_layer* layer;
+
+    /* Get client */
+    client = guac_client_alloc();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(client);
+
+    /* Fill pool */
+    for (i=0; i<GUAC_BUFFER_POOL_INITIAL_SIZE; i++) {
+
+        /* Allocate and throw away a layer (should not disturb buffer alloc) */
+        CU_ASSERT_PTR_NOT_NULL_FATAL(guac_client_alloc_layer(client));
+
+        layer = guac_client_alloc_buffer(client);
+
+        /* Index should be within pool size */
+        CU_ASSERT_PTR_NOT_NULL_FATAL(layer);
+        CU_ASSERT_FATAL(layer->index < 0);
+        CU_ASSERT_FATAL(layer->index >= -GUAC_BUFFER_POOL_INITIAL_SIZE);
+
+        /* This should be a layer we have not seen yet */
+        CU_ASSERT_FALSE(seen[-layer->index - 1]);
+        seen[-layer->index - 1] = true;
+
+        guac_client_free_buffer(client, layer);
+
+    }
+
+    /* Now that pool is filled, we should get a previously seen layer */
+    layer = guac_client_alloc_buffer(client);
+
+    CU_ASSERT_FATAL(layer->index < 0);
+    CU_ASSERT_FATAL(layer->index >= -GUAC_BUFFER_POOL_INITIAL_SIZE);
+    CU_ASSERT_TRUE(seen[-layer->index - 1]);
+
+    /* Free client */
+    guac_client_free(client);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/client/layer_pool.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/client/layer_pool.c b/src/libguac/tests/client/layer_pool.c
new file mode 100644
index 0000000..f82e84f
--- /dev/null
+++ b/src/libguac/tests/client/layer_pool.c
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/client.h>
+#include <guacamole/layer.h>
+
+#include <stdbool.h>
+
+/**
+ * Test which verifies that layers can be allocated and freed using the pool
+ * of layers available to each guac_client, and that doing so does not disturb
+ * the similar pool of buffers.
+ */
+void test_client__layer_pool() {
+
+    guac_client* client;
+
+    int i;
+    bool seen[GUAC_BUFFER_POOL_INITIAL_SIZE] = {0};
+
+    guac_layer* layer;
+
+    /* Get client */
+    client = guac_client_alloc();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(client);
+
+    /* Fill pool */
+    for (i=0; i<GUAC_BUFFER_POOL_INITIAL_SIZE; i++) {
+
+        /* Allocate and throw away a buffer (should not disturb layer alloc) */
+        CU_ASSERT_PTR_NOT_NULL_FATAL(guac_client_alloc_buffer(client));
+
+        layer = guac_client_alloc_layer(client);
+
+        /* Index should be within pool size */
+        CU_ASSERT_PTR_NOT_NULL_FATAL(layer);
+        CU_ASSERT_FATAL(layer->index > 0);
+        CU_ASSERT_FATAL(layer->index <= GUAC_BUFFER_POOL_INITIAL_SIZE);
+
+        /* This should be a layer we have not seen yet */
+        CU_ASSERT_FALSE(seen[layer->index - 1]);
+        seen[layer->index - 1] = true;
+
+        guac_client_free_layer(client, layer);
+
+    }
+
+    /* Now that pool is filled, we should get a previously seen layer */
+    layer = guac_client_alloc_layer(client);
+
+    CU_ASSERT_FATAL(layer->index > 0);
+    CU_ASSERT_FATAL(layer->index <= GUAC_BUFFER_POOL_INITIAL_SIZE);
+    CU_ASSERT_TRUE(seen[layer->index - 1]);
+
+    /* Free client */
+    guac_client_free(client);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/parser/append.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/parser/append.c b/src/libguac/tests/parser/append.c
new file mode 100644
index 0000000..88515c1
--- /dev/null
+++ b/src/libguac/tests/parser/append.c
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/parser.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/**
+ * Test which verifies that guac_parser correctly parses Guacamole instructions
+ * from arbitrary blocks of data passed to guac_parser_append().
+ */
+void test_parser__append() {
+
+    /* Allocate parser */
+    guac_parser* parser = guac_parser_alloc();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(parser);
+
+    /* Instruction input */
+    char buffer[] = "4.test,8.testdata,5.zxcvb,13.guacamoletest;XXXXXXXXXXXXXXXXXX";
+    char* current = buffer;
+
+    /* While data remains */
+    int remaining = sizeof(buffer)-1;
+    while (remaining > 18) {
+
+        /* Parse more data */
+        int parsed = guac_parser_append(parser, current, remaining);
+        if (parsed == 0)
+            break;
+
+        current += parsed;
+        remaining -= parsed;
+
+    }
+
+    /* Parse of instruction should be complete */
+    CU_ASSERT_EQUAL(remaining, 18);
+    CU_ASSERT_EQUAL(parser->state, GUAC_PARSE_COMPLETE);
+
+    /* Parse is complete - no more data should be read */
+    CU_ASSERT_EQUAL(guac_parser_append(parser, current, 18), 0);
+    CU_ASSERT_EQUAL(parser->state, GUAC_PARSE_COMPLETE);
+
+    /* Validate resulting structure */
+    CU_ASSERT_EQUAL(parser->argc, 3);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(parser->opcode);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(parser->argv[0]);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(parser->argv[1]);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(parser->argv[2]);
+
+    /* Validate resulting content */
+    CU_ASSERT_STRING_EQUAL(parser->opcode,  "test");
+    CU_ASSERT_STRING_EQUAL(parser->argv[0], "testdata");
+    CU_ASSERT_STRING_EQUAL(parser->argv[1], "zxcvb");
+    CU_ASSERT_STRING_EQUAL(parser->argv[2], "guacamoletest");
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/parser/read.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/parser/read.c b/src/libguac/tests/parser/read.c
new file mode 100644
index 0000000..e3b254c
--- /dev/null
+++ b/src/libguac/tests/parser/read.c
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/error.h>
+#include <guacamole/parser.h>
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/**
+ * Test string which contains exactly four Unicode characters encoded in UTF-8.
+ * This particular test string uses several characters which encode to multiple
+ * bytes in UTF-8.
+ */
+#define UTF8_4 "\xe7\x8a\xac\xf0\x90\xac\x80z\xc3\xa1"
+
+/**
+ * Writes a series of Guacamole instructions as raw bytes to the given file
+ * descriptor. The instructions written correspond to the instructions verified
+ * by read_expected_instructions(). The given file descriptor is automatically
+ * closed as a result of calling this function.
+ *
+ * @param fd
+ *     The file descriptor to write instructions to.
+ */
+static void write_instructions(int fd) {
+
+    char test_string[] = "4.test,6.a" UTF8_4 "b,"
+                         "5.12345,10.a" UTF8_4 UTF8_4 "c;"
+                         "5.test2,10.hellohello,15.worldworldworld;";
+
+    char* current = test_string;
+    int remaining = sizeof(test_string) - 1;
+
+    /* Write all bytes in test string */
+    while (remaining > 0) {
+
+        /* Bail out immediately if write fails (test will fail in parent
+         * process due to failure to read) */
+        int written = write(fd, current, remaining);
+        if (written <= 0)
+            break;
+
+        current += written;
+        remaining -= written;
+
+    }
+
+    /* Done writing */
+    close(fd);
+
+}
+
+/**
+ * Reads and parses instructions from the given file descriptor using a
+ * guac_socket and guac_parser, verfying that those instructions match the
+ * series of Guacamole instructions expected to be written by
+ * write_instructions(). The given file descriptor is automatically closed as a
+ * result of calling this function.
+ *
+ * @param fd
+ *     The file descriptor to read data from.
+ */
+static void read_expected_instructions(int fd) {
+
+    /* Open guac socket */
+    guac_socket* socket = guac_socket_open(fd);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(socket);
+
+    /* Allocate parser */
+    guac_parser* parser = guac_parser_alloc();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(parser);
+
+    /* Read and validate first instruction */
+    CU_ASSERT_EQUAL_FATAL(guac_parser_read(parser, socket, 1000000), 0);
+    CU_ASSERT_STRING_EQUAL(parser->opcode, "test");
+    CU_ASSERT_EQUAL_FATAL(parser->argc, 3);
+    CU_ASSERT_STRING_EQUAL(parser->argv[0], "a" UTF8_4 "b");
+    CU_ASSERT_STRING_EQUAL(parser->argv[1], "12345");
+    CU_ASSERT_STRING_EQUAL(parser->argv[2], "a" UTF8_4 UTF8_4 "c");
+    
+    /* Read and validate second instruction */
+    CU_ASSERT_EQUAL_FATAL(guac_parser_read(parser, socket, 1000000), 0);
+    CU_ASSERT_STRING_EQUAL(parser->opcode, "test2");
+    CU_ASSERT_EQUAL_FATAL(parser->argc, 2);
+    CU_ASSERT_STRING_EQUAL(parser->argv[0], "hellohello");
+    CU_ASSERT_STRING_EQUAL(parser->argv[1], "worldworldworld");
+
+    /* Done */
+    guac_parser_free(parser);
+    guac_socket_free(socket);
+
+}
+
+/**
+ * Tests that guac_parser_read() correctly reads and parses instructions
+ * received over a guac_socket. A child process is forked to write a series of
+ * instructions which are read and verified by the parent process.
+ */
+void test_parser__read() {
+
+    int fd[2];
+
+    /* Create pipe */
+    CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);
+
+    int read_fd = fd[0];
+    int write_fd = fd[1];
+
+    /* Fork into writer process (child) and reader process (parent) */
+    int childpid;
+    CU_ASSERT_NOT_EQUAL_FATAL((childpid = fork()), -1);
+
+    /* Attempt to write a series of instructions within the child process */
+    if (childpid == 0) {
+        close(read_fd);
+        write_instructions(write_fd);
+        exit(0);
+    }
+
+    /* Read and verify the expected instructions within the parent process */
+    close(write_fd);
+    read_expected_instructions(read_fd);
+ 
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/pool/next_free.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/pool/next_free.c b/src/libguac/tests/pool/next_free.c
new file mode 100644
index 0000000..e8bd945
--- /dev/null
+++ b/src/libguac/tests/pool/next_free.c
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/pool.h>
+
+/**
+ * The number of unique integers to provide through the guac_pool instance
+ * being tested.
+ */
+#define POOL_SIZE 128
+
+/**
+ * Test which verifies that guac_pool provides access to a given number of
+ * unique integers, never repeating a retrieved integer until that integer
+ * is returned to the pool.
+ */
+void test_pool__next_free() {
+
+    guac_pool* pool;
+
+    int i;
+    int seen[POOL_SIZE] = {0};
+    int value;
+
+    /* Get pool */
+    pool = guac_pool_alloc(POOL_SIZE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pool);
+
+    /* Fill pool */
+    for (i=0; i<POOL_SIZE; i++) {
+
+        /* Get value from pool */
+        value = guac_pool_next_int(pool);
+
+        /* Value should be within pool size */
+        CU_ASSERT_FATAL(value >= 0);
+        CU_ASSERT_FATAL(value <  POOL_SIZE);
+
+        /* This should be an integer we have not seen yet */
+        CU_ASSERT_EQUAL(0, seen[value]);
+        seen[value]++;
+
+        /* Return value to pool */
+        guac_pool_free_int(pool, value);
+
+    }
+
+    /* Now that pool is filled, we should get ONLY previously seen integers */
+    for (i=0; i<POOL_SIZE; i++) {
+
+        /* Get value from pool */
+        value = guac_pool_next_int(pool);
+
+        /* Value should be within pool size */
+        CU_ASSERT_FATAL(value >= 0);
+        CU_ASSERT_FATAL(value <  POOL_SIZE);
+
+        /* This should be an integer we have seen only once */
+        CU_ASSERT_EQUAL(1, seen[value]);
+        seen[value]++;
+
+    }
+
+    /* Pool is filled to minimum now. Next value should be equal to size. */
+    value = guac_pool_next_int(pool);
+
+    CU_ASSERT_EQUAL(POOL_SIZE, value);
+
+    /* Free pool */
+    guac_pool_free(pool);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/protocol/base64_decode.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/protocol/base64_decode.c b/src/libguac/tests/protocol/base64_decode.c
new file mode 100644
index 0000000..60c8a03
--- /dev/null
+++ b/src/libguac/tests/protocol/base64_decode.c
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/protocol.h>
+
+/**
+ * Tests that libguac's in-place base64 decoding function properly decodes
+ * valid base64 and fails for invalid base64.
+ */
+void test_protocol__decode_base64() {
+
+    /* Test strings */
+    char test_HELLO[]     = "SEVMTE8=";
+    char test_AVOCADO[]   = "QVZPQ0FETw==";
+    char test_GUACAMOLE[] = "R1VBQ0FNT0xF";
+
+    /* Invalid strings */
+    char invalid1[] = "====";
+    char invalid2[] = "";
+
+    /* Test one character of padding */
+    CU_ASSERT_EQUAL(guac_protocol_decode_base64(test_HELLO), 5);
+    CU_ASSERT_NSTRING_EQUAL(test_HELLO, "HELLO", 5);
+
+    /* Test two characters of padding */
+    CU_ASSERT_EQUAL(guac_protocol_decode_base64(test_AVOCADO), 7);
+    CU_ASSERT_NSTRING_EQUAL(test_AVOCADO, "AVOCADO", 7);
+
+    /* Test three characters of padding */
+    CU_ASSERT_EQUAL(guac_protocol_decode_base64(test_GUACAMOLE), 9);
+    CU_ASSERT_NSTRING_EQUAL(test_GUACAMOLE, "GUACAMOLE", 9);
+
+    /* Verify invalid strings stop early as expected */
+    CU_ASSERT_EQUAL(guac_protocol_decode_base64(invalid1), 0);
+    CU_ASSERT_EQUAL(guac_protocol_decode_base64(invalid2), 0);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/socket/fd_send_instruction.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/socket/fd_send_instruction.c b/src/libguac/tests/socket/fd_send_instruction.c
new file mode 100644
index 0000000..5a162d6
--- /dev/null
+++ b/src/libguac/tests/socket/fd_send_instruction.c
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/**
+ * Test string which contains exactly four Unicode characters encoded in UTF-8.
+ * This particular test string uses several characters which encode to multiple
+ * bytes in UTF-8.
+ */
+#define UTF8_4 "\xe7\x8a\xac\xf0\x90\xac\x80z\xc3\xa1"
+
+/**
+ * Writes a series of Guacamole instructions using a normal guac_socket
+ * wrapping the given file descriptor. The instructions written correspond to
+ * the instructions verified by read_expected_instructions(). The given file
+ * descriptor is automatically closed as a result of calling this function.
+ *
+ * @param fd
+ *     The file descriptor to write instructions to.
+ */
+static void write_instructions(int fd) {
+
+    /* Open guac socket */
+    guac_socket* socket = guac_socket_open(fd);
+
+    /* Write nothing if socket cannot be allocated (test will fail in parent
+     * process due to failure to read) */
+    if (socket == NULL) {
+        close(fd);
+        return;
+    }
+
+    /* Write instructions */
+    guac_protocol_send_name(socket, "a" UTF8_4 "b" UTF8_4 "c");
+    guac_protocol_send_sync(socket, 12345);
+    guac_socket_flush(socket);
+
+    /* Close and free socket */
+    guac_socket_free(socket);
+
+}
+
+/**
+ * Reads raw bytes from the given file descriptor until no further bytes
+ * remain, verfying that those bytes represent the series of Guacamole
+ * instructions expected to be written by write_instructions(). The given
+ * file descriptor is automatically closed as a result of calling this
+ * function.
+ *
+ * @param fd
+ *     The file descriptor to read data from.
+ */
+static void read_expected_instructions(int fd) {
+
+    char expected[] =
+        "4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
+        "4.sync,5.12345;";
+
+    int numread;
+    char buffer[1024];
+    int offset = 0;
+
+    /* Read everything available into buffer */
+    while ((numread = read(fd, &(buffer[offset]),
+                    sizeof(buffer) - offset)) > 0) {
+        offset += numread;
+    }
+
+    /* Verify length of read data */
+    CU_ASSERT_EQUAL(offset, strlen(expected));
+
+    /* Add NULL terminator */
+    buffer[offset] = '\0';
+
+    /* Read value should be equal to expected value */
+    CU_ASSERT_STRING_EQUAL(buffer, expected);
+
+    /* File descriptor is no longer needed */
+    close(fd);
+
+}
+
+/**
+ * Tests that the file descriptor implementation of guac_socket properly
+ * implements writing of instructions. A child process is forked to write a
+ * series of instructions which are read and verified by the parent process.
+ */
+void test_socket__fd_send_instruction() {
+
+    int fd[2];
+
+    /* Create pipe */
+    CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);
+
+    int read_fd = fd[0];
+    int write_fd = fd[1];
+
+    /* Fork into writer process (child) and reader process (parent) */
+    int childpid;
+    CU_ASSERT_NOT_EQUAL_FATAL((childpid = fork()), -1);
+
+    /* Attempt to write a series of instructions within the child process */
+    if (childpid == 0) {
+        close(read_fd);
+        write_instructions(write_fd);
+        exit(0);
+    }
+
+    /* Read and verify the expected instructions within the parent process */
+    close(write_fd);
+    read_expected_instructions(read_fd);
+ 
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/socket/nested_send_instruction.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/socket/nested_send_instruction.c b/src/libguac/tests/socket/nested_send_instruction.c
new file mode 100644
index 0000000..db29e2b
--- /dev/null
+++ b/src/libguac/tests/socket/nested_send_instruction.c
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/**
+ * Test string which contains exactly four Unicode characters encoded in UTF-8.
+ * This particular test string uses several characters which encode to multiple
+ * bytes in UTF-8.
+ */
+#define UTF8_4 "\xe7\x8a\xac\xf0\x90\xac\x80z\xc3\xa1"
+
+/**
+ * Writes a series of Guacamole instructions using a nested guac_socket
+ * wrapping another guac_socket which writes to the given file descriptor. The
+ * instructions written correspond to the instructions verified by
+ * read_expected_instructions(). The given file descriptor is automatically
+ * closed as a result of calling this function.
+ *
+ * @param fd
+ *     The file descriptor to write instructions to.
+ */
+static void write_instructions(int fd) {
+
+    /* Open guac socket */
+    guac_socket* socket = guac_socket_open(fd);
+
+    /* Write nothing if socket cannot be allocated (test will fail in parent
+     * process due to failure to read) */
+    if (socket == NULL) {
+        close(fd);
+        return;
+    }
+
+    /* Nest socket */
+    guac_socket* nested_socket = guac_socket_nest(socket, 123);
+
+    /* Write nothing if nested socket cannot be allocated (test will fail in
+     * parent process due to failure to read) */
+    if (socket == NULL) {
+        guac_socket_free(socket);
+        return;
+    }
+
+    /* Write instructions */
+    guac_protocol_send_name(nested_socket, "a" UTF8_4 "b" UTF8_4 "c");
+    guac_protocol_send_sync(nested_socket, 12345);
+
+    /* Close and free sockets */
+    guac_socket_free(nested_socket);
+    guac_socket_free(socket);
+
+}
+
+/**
+ * Reads raw bytes from the given file descriptor until no further bytes
+ * remain, verfying that those bytes represent the series of Guacamole
+ * instructions expected to be written by write_instructions(). The given
+ * file descriptor is automatically closed as a result of calling this
+ * function.
+ *
+ * @param fd
+ *     The file descriptor to read data from.
+ */
+static void read_expected_instructions(int fd) {
+
+    char expected[] =
+        "4.nest,3.123,37."
+            "4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
+            "4.sync,5.12345;"
+        ";";
+
+    int numread;
+    char buffer[1024];
+    int offset = 0;
+
+    /* Read everything available into buffer */
+    while ((numread = read(fd, &(buffer[offset]),
+                    sizeof(buffer) - offset)) > 0) {
+        offset += numread;
+    }
+
+    /* Verify length of read data */
+    CU_ASSERT_EQUAL(offset, strlen(expected));
+
+    /* Add NULL terminator */
+    buffer[offset] = '\0';
+
+    /* Read value should be equal to expected value */
+    CU_ASSERT_STRING_EQUAL(buffer, expected);
+
+    /* File descriptor is no longer needed */
+    close(fd);
+
+}
+
+/**
+ * Tests that the nested socket implementation of guac_socket properly
+ * implements writing of instructions. A child process is forked to write a
+ * series of instructions which are read and verified by the parent process.
+ */
+void test_socket__nested_send_instruction() {
+
+    int fd[2];
+
+    /* Create pipe */
+    CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);
+
+    int read_fd = fd[0];
+    int write_fd = fd[1];
+
+    /* Fork into writer process (child) and reader process (parent) */
+    int childpid;
+    CU_ASSERT_NOT_EQUAL_FATAL((childpid = fork()), -1);
+
+    /* Attempt to write a series of instructions within the child process */
+    if (childpid == 0) {
+        close(read_fd);
+        write_instructions(write_fd);
+        exit(0);
+    }
+
+    /* Read and verify the expected instructions within the parent process */
+    close(write_fd);
+    read_expected_instructions(read_fd);
+ 
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/unicode/charsize.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/unicode/charsize.c b/src/libguac/tests/unicode/charsize.c
new file mode 100644
index 0000000..e636155
--- /dev/null
+++ b/src/libguac/tests/unicode/charsize.c
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/unicode.h>
+
+/**
+ * Test which verifies that guac_utf8_charsize() correctly determines the
+ * length of UTF-8 characters from the leading byte of that character.
+ */
+void test_unicode__utf8_charsize() {
+    CU_ASSERT_EQUAL(1, guac_utf8_charsize('g'));
+    CU_ASSERT_EQUAL(2, guac_utf8_charsize('\xC4'));
+    CU_ASSERT_EQUAL(3, guac_utf8_charsize('\xE7'));
+    CU_ASSERT_EQUAL(4, guac_utf8_charsize('\xF0'));
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/unicode/read.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/unicode/read.c b/src/libguac/tests/unicode/read.c
new file mode 100644
index 0000000..230a721
--- /dev/null
+++ b/src/libguac/tests/unicode/read.c
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/unicode.h>
+
+/**
+ * Test which verifies that guac_utf8_read() properly parses UTF-8.
+ */
+void test_unicode__utf8_read() {
+
+    int codepoint;
+
+    char buffer[16] =
+        /* U+0065  */ "\x65"
+        /* U+0654  */ "\xD9\x94"
+        /* U+0876  */ "\xE0\xA1\xB6"
+        /* U+12345 */ "\xF0\x92\x8D\x85";
+
+    CU_ASSERT_EQUAL(1, guac_utf8_read(&(buffer[0]), 10, &codepoint));
+    CU_ASSERT_EQUAL(0x0065, codepoint);
+
+    CU_ASSERT_EQUAL(2, guac_utf8_read(&(buffer[1]),  9, &codepoint));
+    CU_ASSERT_EQUAL(0x0654, codepoint);
+
+    CU_ASSERT_EQUAL(3, guac_utf8_read(&(buffer[3]),  7, &codepoint));
+    CU_ASSERT_EQUAL(0x0876, codepoint);
+
+    CU_ASSERT_EQUAL(4, guac_utf8_read(&(buffer[6]),  4, &codepoint));
+    CU_ASSERT_EQUAL(0x12345, codepoint);
+
+    CU_ASSERT_EQUAL(0, guac_utf8_read(&(buffer[10]), 0, &codepoint));
+    CU_ASSERT_EQUAL(0x12345, codepoint);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/unicode/strlen.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/unicode/strlen.c b/src/libguac/tests/unicode/strlen.c
new file mode 100644
index 0000000..995a503
--- /dev/null
+++ b/src/libguac/tests/unicode/strlen.c
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/unicode.h>
+
+/**
+ * A single Unicode character encoded as one byte with UTF-8.
+ */
+#define UTF8_1b "g"
+
+/**
+ * A single Unicode character encoded as two bytes with UTF-8.
+ */
+#define UTF8_2b "\xc4\xa3"
+
+/**
+ * A single Unicode character encoded as three bytes with UTF-8.
+ */
+#define UTF8_3b "\xe7\x8a\xac"
+
+/**
+ * A single Unicode character encoded as four bytes with UTF-8.
+ */
+#define UTF8_4b "\xf0\x90\x84\xa3"
+
+/**
+ * Test which verifies that guac_utf8_strlen() properly calculates the length
+ * of UTF-8 strings.
+ */
+void test_unicode__utf8_strlen() {
+    CU_ASSERT_EQUAL(0, guac_utf8_strlen(""));
+    CU_ASSERT_EQUAL(1, guac_utf8_strlen(UTF8_4b));
+    CU_ASSERT_EQUAL(2, guac_utf8_strlen(UTF8_4b UTF8_1b));
+    CU_ASSERT_EQUAL(2, guac_utf8_strlen(UTF8_2b UTF8_3b));
+    CU_ASSERT_EQUAL(3, guac_utf8_strlen(UTF8_1b UTF8_3b UTF8_4b));
+    CU_ASSERT_EQUAL(3, guac_utf8_strlen(UTF8_2b UTF8_1b UTF8_3b));
+    CU_ASSERT_EQUAL(3, guac_utf8_strlen(UTF8_4b UTF8_2b UTF8_1b));
+    CU_ASSERT_EQUAL(3, guac_utf8_strlen(UTF8_3b UTF8_4b UTF8_2b));
+    CU_ASSERT_EQUAL(5, guac_utf8_strlen("hello"));
+    CU_ASSERT_EQUAL(9, guac_utf8_strlen("guacamole"));
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/src/libguac/tests/unicode/write.c
----------------------------------------------------------------------
diff --git a/src/libguac/tests/unicode/write.c b/src/libguac/tests/unicode/write.c
new file mode 100644
index 0000000..8480086
--- /dev/null
+++ b/src/libguac/tests/unicode/write.c
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <CUnit/CUnit.h>
+#include <guacamole/unicode.h>
+
+/**
+ * Test which verifies that guac_utf8_write() properly encodes Unicode
+ * codepoints as UTF-8.
+ */
+void test_unicode__utf8_write() {
+
+    char buffer[16];
+
+    /* Test writes */
+    CU_ASSERT_EQUAL(1, guac_utf8_write(0x00065, &(buffer[0]),  10));
+    CU_ASSERT_EQUAL(2, guac_utf8_write(0x00654, &(buffer[1]),   9));
+    CU_ASSERT_EQUAL(3, guac_utf8_write(0x00876, &(buffer[3]),   7));
+    CU_ASSERT_EQUAL(4, guac_utf8_write(0x12345, &(buffer[6]),   4));
+    CU_ASSERT_EQUAL(0, guac_utf8_write(0x00066, &(buffer[10]),  0));
+
+    /* Test result of write */
+    CU_ASSERT(memcmp("\x65",             &(buffer[0]), 1) == 0); /* U+0065  */
+    CU_ASSERT(memcmp("\xD9\x94",         &(buffer[1]), 2) == 0); /* U+0654  */
+    CU_ASSERT(memcmp("\xE0\xA1\xB6",     &(buffer[3]), 3) == 0); /* U+0876  */
+    CU_ASSERT(memcmp("\xF0\x92\x8D\x85", &(buffer[6]), 4) == 0); /* U+12345 */
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/tests/Makefile.am
----------------------------------------------------------------------
diff --git a/tests/Makefile.am b/tests/Makefile.am
deleted file mode 100644
index fc1302e..0000000
--- a/tests/Makefile.am
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
-# into Makefile.in. Though the build system (GNU Autotools) automatically adds
-# its own license boilerplate to the generated Makefile.in, that boilerplate
-# does not apply to the transcluded portions of Makefile.am which are licensed
-# to you by the ASF under the Apache License, Version 2.0, as described above.
-#
-
-AUTOMAKE_OPTIONS = foreign 
-ACLOCAL_AMFLAGS = -I m4
-
-TESTS = test_libguac
-check_PROGRAMS = test_libguac
-
-noinst_HEADERS =          \
-    client/client_suite.h \
-    common/common_suite.h \
-    protocol/suite.h      \
-    util/util_suite.h
-
-test_libguac_SOURCES =           \
-    test_libguac.c               \
-    client/client_suite.c        \
-    client/buffer_pool.c         \
-    client/layer_pool.c          \
-    common/common_suite.c        \
-    common/guac_iconv.c          \
-    common/guac_string.c         \
-    common/guac_rect.c           \
-    protocol/suite.c             \
-    protocol/base64_decode.c     \
-    protocol/instruction_parse.c \
-    protocol/instruction_read.c  \
-    protocol/instruction_write.c \
-    protocol/nest_write.c        \
-    util/util_suite.c            \
-    util/guac_pool.c             \
-    util/guac_unicode.c
-
-test_libguac_CFLAGS =       \
-    -Werror -Wall -pedantic \
-    @COMMON_INCLUDE@        \
-    @LIBGUAC_INCLUDE@
-
-test_libguac_LDADD = \
-    @COMMON_LTLIB@   \
-    @CUNIT_LIBS@     \
-    @LIBGUAC_LTLIB@
-

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/tests/client/buffer_pool.c
----------------------------------------------------------------------
diff --git a/tests/client/buffer_pool.c b/tests/client/buffer_pool.c
deleted file mode 100644
index df27f6e..0000000
--- a/tests/client/buffer_pool.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "config.h"
-
-#include "client_suite.h"
-
-#include <CUnit/Basic.h>
-#include <guacamole/client.h>
-#include <guacamole/layer.h>
-
-void test_buffer_pool() {
-
-    guac_client* client;
-
-    int i;
-    int seen[GUAC_BUFFER_POOL_INITIAL_SIZE] = {0};
-
-    guac_layer* layer;
-
-    /* Get client */
-    client = guac_client_alloc();
-    CU_ASSERT_PTR_NOT_NULL_FATAL(client);
-
-    /* Fill pool */
-    for (i=0; i<GUAC_BUFFER_POOL_INITIAL_SIZE; i++) {
-
-        /* Allocate and throw away a layer (should not disturb buffer alloc) */
-        CU_ASSERT_PTR_NOT_NULL_FATAL(guac_client_alloc_layer(client));
-
-        layer = guac_client_alloc_buffer(client);
-
-        /* Index should be within pool size */
-        CU_ASSERT_PTR_NOT_NULL_FATAL(layer);
-        CU_ASSERT_FATAL(layer->index < 0);
-        CU_ASSERT_FATAL(layer->index >= -GUAC_BUFFER_POOL_INITIAL_SIZE);
-
-        /* This should be a layer we have not seen yet */
-        CU_ASSERT_FALSE(seen[-layer->index - 1]);
-        seen[-layer->index - 1] = 1;
-
-        guac_client_free_buffer(client, layer);
-
-    }
-
-    /* Now that pool is filled, we should get a previously seen layer */
-    layer = guac_client_alloc_buffer(client);
-
-    CU_ASSERT_FATAL(layer->index < 0);
-    CU_ASSERT_FATAL(layer->index >= -GUAC_BUFFER_POOL_INITIAL_SIZE);
-    CU_ASSERT_TRUE(seen[-layer->index - 1]);
-
-    /* Free client */
-    guac_client_free(client);
-
-}
-

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/476b4310/tests/client/client_suite.c
----------------------------------------------------------------------
diff --git a/tests/client/client_suite.c b/tests/client/client_suite.c
deleted file mode 100644
index 18bba6b..0000000
--- a/tests/client/client_suite.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "config.h"
-
-#include "client_suite.h"
-
-#include <CUnit/Basic.h>
-
-int client_suite_init() {
-    return 0;
-}
-
-int client_suite_cleanup() {
-    return 0;
-}
-
-int register_client_suite() {
-
-    /* Add client test suite */
-    CU_pSuite suite = CU_add_suite("client",
-            client_suite_init, client_suite_cleanup);
-    if (suite == NULL) {
-        CU_cleanup_registry();
-        return CU_get_error();
-    }
-
-    /* Add tests */
-    if (
-        CU_add_test(suite, "layer-pool", test_layer_pool) == NULL
-     || CU_add_test(suite, "buffer-pool", test_buffer_pool) == NULL
-       ) {
-        CU_cleanup_registry();
-        return CU_get_error();
-    }
-
-    return 0;
-
-}
-