GUACAMOLE-662: Merge fix handling of unit tests within buid.

This commit is contained in:
Nick Couchman 2019-01-06 19:42:12 -05:00
commit aba7b987d3
40 changed files with 1520 additions and 1198 deletions

15
.gitignore vendored
View File

@ -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

View File

@ -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
@ -99,5 +97,6 @@ EXTRA_DIST = \
NOTICE \
bin/guacctl \
doc/Doxyfile.in \
src/guacd-docker
src/guacd-docker \
util/generate-test-runner.pl

89
README-unit-testing.md Normal file
View File

@ -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.

View File

@ -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

9
src/common/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
# Auto-generated test runner and binary
_generated_runner.c
test_common
# Test suite output
*.log
*.trs

View File

@ -27,6 +27,7 @@ AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
noinst_LTLIBRARIES = libguac_common.la
SUBDIRS = . tests
noinst_HEADERS = \
common/io.h \

View File

@ -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

View File

@ -17,15 +17,75 @@
* under the License.
*/
#include "config.h"
#include "common_suite.h"
#include "common/iconv.h"
#include <stdlib.h>
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
static void test_conversion(
/**
* 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) {
@ -50,77 +110,74 @@ static void test_conversion(
}
void test_guac_iconv() {
/* 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
};
/* UTF8 identity */
test_conversion(
/**
* 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));
}
/* UTF16 identity */
test_conversion(
GUAC_READ_UTF16, test_string_utf16, sizeof(test_string_utf16),
GUAC_WRITE_UTF16, test_string_utf16, sizeof(test_string_utf16));
/* UTF8 to UTF16 */
test_conversion(
/**
* 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));
}
/* UTF16 to UTF8 */
test_conversion(
/**
* 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));
}
/* UTF16 to ISO-8859-1 */
test_conversion(
/**
* 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));
}
/* UTF16 to CP1252 */
test_conversion(
/**
* 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));
}
/* CP1252 to UTF8 */
test_conversion(
/**
* 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));
}
/* ISO-8859-1 to UTF8 */
test_conversion(
/**
* 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));

View File

@ -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);
}

View File

@ -17,31 +17,27 @@
* under the License.
*/
#include "config.h"
#include "common/rect.h"
#include "client/client_suite.h"
#include "common/common_suite.h"
#include "protocol/suite.h"
#include "util/util_suite.h"
#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>
/**
* Test which verifies that guac_common_rect_constrain() restricts a given
* rectangle to arbitrary bounds.
*/
void test_rect__constrain() {
int main() {
guac_common_rect max;
guac_common_rect rect;
/* Init registry */
if (CU_initialize_registry() != CUE_SUCCESS)
return CU_get_error();
guac_common_rect_init(&rect, -10, -10, 110, 110);
guac_common_rect_init(&max, 0, 0, 100, 100);
guac_common_rect_constrain(&rect, &max);
/* Register suites */
register_protocol_suite();
register_client_suite();
register_util_suite();
/* Run tests */
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_cleanup_registry();
return CU_get_error();
CU_ASSERT_EQUAL(0, rect.x);
CU_ASSERT_EQUAL(0, rect.y);
CU_ASSERT_EQUAL(100, rect.width);
CU_ASSERT_EQUAL(100, rect.height);
}

View File

@ -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);
}

View File

@ -17,39 +17,26 @@
* under the License.
*/
#include "common/rect.h"
#ifndef _GUAC_TEST_COMMON_SUITE_H
#define _GUAC_TEST_COMMON_SUITE_H
#include <CUnit/CUnit.h>
/**
* Test suite containing unit tests for the "common" utility library included
* for the sake of simplifying guacamole-server development, but not included
* as part of libguac.
*
* @file common_suite.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() {
#include "config.h"
guac_common_rect max;
guac_common_rect rect;
/**
* Registers the common test suite with CUnit.
*/
int register_common_suite();
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);
/**
* Unit test for string utility functions.
*/
void test_guac_string();
/**
* Unit test for character conversion functions.
*/
void test_guac_iconv();
/**
* Unit test for rectangle calculation functions.
*/
void test_guac_rect();
#endif
}

View File

@ -17,16 +17,23 @@
* under the License.
*/
#include "common/rect.h"
#ifndef _GUAC_TEST_CLIENT_SUITE_H
#define _GUAC_TEST_CLIENT_SUITE_H
#include <CUnit/CUnit.h>
#include "config.h"
/**
* Test which verifies rectangle initialization via guac_common_rect_init().
*/
void test_rect__init() {
int register_client_suite();
guac_common_rect max;
void test_layer_pool();
void test_buffer_pool();
guac_common_rect_init(&max, 0, 0, 100, 100);
#endif
CU_ASSERT_EQUAL(0, max.x);
CU_ASSERT_EQUAL(0, max.y);
CU_ASSERT_EQUAL(100, max.width);
CU_ASSERT_EQUAL(100, max.height);
}

View File

@ -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);
}

View File

@ -17,27 +17,17 @@
* under the License.
*/
#include "common/string.h"
#ifndef _GUAC_TEST_PROTOCOL_SUITE_H
#define _GUAC_TEST_PROTOCOL_SUITE_H
#include <CUnit/CUnit.h>
#include "config.h"
/* Unicode (UTF-8) strings */
#define UTF8_1 "\xe7\x8a\xac" /* One character */
#define UTF8_2 UTF8_1 "\xf0\x90\xac\x80" /* Two characters */
#define UTF8_3 UTF8_2 "z" /* Three characters */
#define UTF8_4 UTF8_3 "\xc3\xa1" /* Four characters */
#define UTF8_8 UTF8_4 UTF8_4 /* Eight characters */
int register_protocol_suite();
void test_base64_decode();
void test_instruction_parse();
void test_instruction_read();
void test_instruction_write();
void test_nest_write();
#endif
/**
* 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'));
}

View File

@ -17,26 +17,20 @@
* under the License.
*/
#include "config.h"
#include "common_suite.h"
#include "common/string.h"
#include <CUnit/CUnit.h>
#include <stdlib.h>
#include <CUnit/Basic.h>
void test_guac_string() {
char** tokens;
/* Test occurrence counting */
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'));
/**
* Test which verifies that guac_split() splits a string on occurrences of a
* given character.
*/
void test_string__split() {
/* Split test string */
tokens = guac_split("this is a test string", ' ');
char** tokens = guac_split("this is a test string", ' ');
CU_ASSERT_PTR_NOT_NULL(tokens);
/* Check resulting tokens */
@ -57,7 +51,6 @@ void test_guac_string() {
CU_ASSERT_PTR_NULL(tokens[5]);
/* Clean up */
free(tokens[0]);
free(tokens[1]);

View File

@ -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

View File

@ -27,6 +27,7 @@ AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libguac.la
SUBDIRS = . tests
libguacincdir = $(includedir)/guacamole

View File

@ -26,41 +26,51 @@
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
TESTS = test_libguac
check_PROGRAMS = test_libguac
#
# Unit tests for libguac
#
noinst_HEADERS = \
client/client_suite.h \
common/common_suite.h \
protocol/suite.h \
util/util_suite.h
check_PROGRAMS = test_libguac
TESTS = $(check_PROGRAMS)
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 \
parser/append.c \
parser/read.c \
pool/next_free.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
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 \
@COMMON_INCLUDE@ \
@LIBGUAC_INCLUDE@
test_libguac_LDADD = \
@COMMON_LTLIB@ \
@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

View File

@ -17,20 +17,23 @@
* under the License.
*/
#include "config.h"
#include "client_suite.h"
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <guacamole/client.h>
#include <guacamole/layer.h>
void test_buffer_pool() {
#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;
int seen[GUAC_BUFFER_POOL_INITIAL_SIZE] = {0};
bool seen[GUAC_BUFFER_POOL_INITIAL_SIZE] = { 0 };
guac_layer* layer;
@ -53,7 +56,7 @@ void test_buffer_pool() {
/* This should be a layer we have not seen yet */
CU_ASSERT_FALSE(seen[-layer->index - 1]);
seen[-layer->index - 1] = 1;
seen[-layer->index - 1] = true;
guac_client_free_buffer(client, layer);

View File

@ -17,20 +17,23 @@
* under the License.
*/
#include "config.h"
#include "client_suite.h"
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <guacamole/client.h>
#include <guacamole/layer.h>
void test_layer_pool() {
#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;
int seen[GUAC_BUFFER_POOL_INITIAL_SIZE] = {0};
bool seen[GUAC_BUFFER_POOL_INITIAL_SIZE] = {0};
guac_layer* layer;
@ -53,7 +56,7 @@ void test_layer_pool() {
/* This should be a layer we have not seen yet */
CU_ASSERT_FALSE(seen[layer->index - 1]);
seen[layer->index - 1] = 1;
seen[layer->index - 1] = true;
guac_client_free_layer(client, layer);

View File

@ -17,18 +17,18 @@
* under the License.
*/
#include "config.h"
#include "suite.h"
#include <CUnit/CUnit.h>
#include <guacamole/parser.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <CUnit/Basic.h>
#include <guacamole/parser.h>
void test_instruction_parse() {
/**
* 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();
@ -52,6 +52,7 @@ void test_instruction_parse() {
}
/* Parse of instruction should be complete */
CU_ASSERT_EQUAL(remaining, 18);
CU_ASSERT_EQUAL(parser->state, GUAC_PARSE_COMPLETE);

View File

@ -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);
}

View File

@ -17,20 +17,21 @@
* under the License.
*/
#include "config.h"
#include "util_suite.h"
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <guacamole/pool.h>
#define UNSEEN 0
#define SEEN_PHASE_1 1
#define SEEN_PHASE_2 2
/**
* The number of unique integers to provide through the guac_pool instance
* being tested.
*/
#define POOL_SIZE 128
void test_guac_pool() {
/**
* 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;
@ -53,8 +54,8 @@ void test_guac_pool() {
CU_ASSERT_FATAL(value < POOL_SIZE);
/* This should be an integer we have not seen yet */
CU_ASSERT_EQUAL(UNSEEN, seen[value]);
seen[value] = SEEN_PHASE_1;
CU_ASSERT_EQUAL(0, seen[value]);
seen[value]++;
/* Return value to pool */
guac_pool_free_int(pool, value);
@ -71,9 +72,9 @@ void test_guac_pool() {
CU_ASSERT_FATAL(value >= 0);
CU_ASSERT_FATAL(value < POOL_SIZE);
/* This should be an integer we have seen already */
CU_ASSERT_EQUAL(SEEN_PHASE_1, seen[value]);
seen[value] = SEEN_PHASE_2;
/* This should be an integer we have seen only once */
CU_ASSERT_EQUAL(1, seen[value]);
seen[value]++;
}

View File

@ -17,18 +17,14 @@
* under the License.
*/
#include "config.h"
#include "suite.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <guacamole/protocol.h>
void test_base64_decode() {
/**
* 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=";

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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'));
}

View File

@ -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);
}

View File

@ -17,19 +17,8 @@
* under the License.
*/
#ifndef _GUAC_TEST_UTIL_SUITE_H
#define _GUAC_TEST_UTIL_SUITE_H
/**
* Test suite containing unit tests for utility functions built into libguac.
* These utility functions are included for convenience rather as integral
* requirements of the core.
*
* @file util_suite.h
*/
#include "config.h"
#include <CUnit/CUnit.h>
#include <guacamole/unicode.h>
/**
* A single Unicode character encoded as one byte with UTF-8.
@ -52,24 +41,19 @@
#define UTF8_4b "\xf0\x90\x84\xa3"
/**
* Registers the utility test suite with CUnit.
* Test which verifies that guac_utf8_strlen() properly calculates the length
* of UTF-8 strings.
*/
int register_util_suite();
/**
* Unit test for the guac_pool structure and related functions. The guac_pool
* structure provides a consistent source of pooled integers. This unit test
* checks that the associated functions behave as documented (returning
* integers in the proper order, allocating new integers as necessary, etc.).
*/
void test_guac_pool();
/**
* Unit test for libguac's Unicode convenience functions. This test checks that
* the functions provided for determining string length, character length, and
* for reading and writing UTF-8 behave as specified in the documentation.
*/
void test_guac_unicode();
#endif
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"));
}

View File

@ -17,36 +17,17 @@
* under the License.
*/
#include "config.h"
#include "util_suite.h"
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <guacamole/unicode.h>
void test_guac_unicode() {
/**
* Test which verifies that guac_utf8_write() properly encodes Unicode
* codepoints as UTF-8.
*/
void test_unicode__utf8_write() {
int codepoint;
char buffer[16];
/* Test character length */
CU_ASSERT_EQUAL(1, guac_utf8_charsize(UTF8_1b[0]));
CU_ASSERT_EQUAL(2, guac_utf8_charsize(UTF8_2b[0]));
CU_ASSERT_EQUAL(3, guac_utf8_charsize(UTF8_3b[0]));
CU_ASSERT_EQUAL(4, guac_utf8_charsize(UTF8_4b[0]));
/* Test string length */
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"));
/* Test writes */
CU_ASSERT_EQUAL(1, guac_utf8_write(0x00065, &(buffer[0]), 10));
CU_ASSERT_EQUAL(2, guac_utf8_write(0x00654, &(buffer[1]), 9));
@ -60,22 +41,5 @@ void test_guac_unicode() {
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 */
/* Test reads */
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);
}

View File

@ -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;
}

View File

@ -1,57 +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 "common_suite.h"
#include <CUnit/Basic.h>
int common_suite_init() {
return 0;
}
int common_suite_cleanup() {
return 0;
}
int register_common_suite() {
/* Add common test suite */
CU_pSuite suite = CU_add_suite("common",
common_suite_init, common_suite_cleanup);
if (suite == NULL) {
CU_cleanup_registry();
return CU_get_error();
}
/* Add tests */
if (
CU_add_test(suite, "guac-iconv", test_guac_iconv) == NULL
|| CU_add_test(suite, "guac-string", test_guac_string) == NULL
|| CU_add_test(suite, "guac-rect", test_guac_rect) == NULL
) {
CU_cleanup_registry();
return CU_get_error();
}
return 0;
}

View File

@ -1,289 +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 "common_suite.h"
#include "common/rect.h"
#include <stdlib.h>
#include <stdio.h>
#include <CUnit/Basic.h>
void test_guac_rect() {
guac_common_rect max;
/*
* Test init method
*/
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);
/*
* Test constrain method
*/
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);
/*
* Test extend method
*/
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);
/*
* Test adjust method
*/
int cell_size = 16;
/* 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);
/*
* Rectangle intersection tests
*/
guac_common_rect min;
guac_common_rect_init(&min, 10, 10, 10, 10);
/* Rectangle intersection - empty
* rectangle is outside */
guac_common_rect_init(&rect, 25, 25, 5, 5);
int 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);
/*
* Basic test of clip and split method
*/
guac_common_rect_init(&min, 10, 10, 10, 10);
guac_common_rect cut;
/* 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);
}

View File

@ -1,108 +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 "suite.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <CUnit/Basic.h>
#include <guacamole/error.h>
#include <guacamole/parser.h>
#include <guacamole/protocol.h>
#include <guacamole/socket.h>
void test_instruction_read() {
int rfd, wfd;
int fd[2], childpid;
char test_string[] = "4.test,6.a" UTF8_4 "b,"
"5.12345,10.a" UTF8_8 "c;"
"5.test2,10.hellohello,15.worldworldworld;";
/* Create pipe */
CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);
/* File descriptors */
rfd = fd[0];
wfd = fd[1];
/* Fork */
if ((childpid = fork()) == -1) {
/* ERROR */
perror("fork");
return;
}
/* Child (pipe writer) */
if (childpid != 0) {
close(rfd);
CU_ASSERT_EQUAL(
write(wfd, test_string, sizeof(test_string)),
sizeof(test_string)
);
exit(0);
}
/* Parent (unit test) */
else {
guac_socket* socket;
guac_parser* parser;
close(wfd);
/* Open guac socket */
socket = guac_socket_open(rfd);
CU_ASSERT_PTR_NOT_NULL_FATAL(socket);
/* Allocate parser */
parser = guac_parser_alloc();
CU_ASSERT_PTR_NOT_NULL_FATAL(parser);
/* Read instruction */
CU_ASSERT_EQUAL_FATAL(guac_parser_read(parser, socket, 1000000), 0);
/* Validate contents */
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_8 "c");
/* Read another instruction */
CU_ASSERT_EQUAL_FATAL(guac_parser_read(parser, socket, 1000000), 0);
/* Validate contents */
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");
guac_parser_free(parser);
guac_socket_free(socket);
}
}

View File

@ -1,101 +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 "suite.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <CUnit/Basic.h>
#include <guacamole/error.h>
#include <guacamole/protocol.h>
#include <guacamole/socket.h>
void test_instruction_write() {
int rfd, wfd;
int fd[2], childpid;
/* Create pipe */
CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);
/* File descriptors */
rfd = fd[0];
wfd = fd[1];
/* Fork */
if ((childpid = fork()) == -1) {
/* ERROR */
perror("fork");
return;
}
/* Child (pipe writer) */
if (childpid != 0) {
guac_socket* socket;
close(rfd);
/* Open guac socket */
socket = guac_socket_open(wfd);
/* Write instruction */
guac_protocol_send_name(socket, "a" UTF8_4 "b" UTF8_4 "c");
guac_protocol_send_sync(socket, 12345);
guac_socket_flush(socket);
guac_socket_free(socket);
exit(0);
}
/* Parent (unit test) */
else {
char expected[] =
"4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
"4.sync,5.12345;";
int numread;
char buffer[1024];
int offset = 0;
close(wfd);
/* Read everything available into buffer */
while ((numread =
read(rfd,
&(buffer[offset]),
sizeof(buffer)-offset)) != 0) {
offset += numread;
}
/* Add NULL terminator */
buffer[offset] = '\0';
/* Read value should be equal to expected value */
CU_ASSERT_STRING_EQUAL(buffer, expected);
}
}

View File

@ -1,109 +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 "suite.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <CUnit/Basic.h>
#include <guacamole/error.h>
#include <guacamole/protocol.h>
#include <guacamole/socket.h>
void test_nest_write() {
int rfd, wfd;
int fd[2], childpid;
/* Create pipe */
CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);
/* File descriptors */
rfd = fd[0];
wfd = fd[1];
/* Fork */
if ((childpid = fork()) == -1) {
/* ERROR */
perror("fork");
return;
}
/* Child (pipe writer) */
if (childpid != 0) {
guac_socket* nested_socket;
guac_socket* socket;
close(rfd);
/* Open guac socket */
socket = guac_socket_open(wfd);
/* Nest socket */
nested_socket = guac_socket_nest(socket, 0);
/* Write instruction */
guac_protocol_send_name(nested_socket, "a" UTF8_4 "b" UTF8_4 "c");
guac_protocol_send_sync(nested_socket, 12345);
guac_socket_flush(nested_socket);
guac_socket_flush(socket);
guac_socket_free(nested_socket);
guac_socket_free(socket);
exit(0);
}
/* Parent (unit test) */
else {
char expected[] =
"4.nest,1.0,37."
"4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
"4.sync,5.12345;"
";";
int numread;
char buffer[1024];
int offset = 0;
close(wfd);
/* Read everything available into buffer */
while ((numread =
read(rfd,
&(buffer[offset]),
sizeof(buffer)-offset)) != 0) {
offset += numread;
}
/* Add NULL terminator */
buffer[offset] = '\0';
/* Read value should be equal to expected value */
CU_ASSERT_STRING_EQUAL(buffer, expected);
}
}

View File

@ -1,59 +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 "suite.h"
#include <CUnit/Basic.h>
int protocol_suite_init() {
return 0;
}
int protocol_suite_cleanup() {
return 0;
}
int register_protocol_suite() {
/* Add protocol test suite */
CU_pSuite suite = CU_add_suite("protocol",
protocol_suite_init, protocol_suite_cleanup);
if (suite == NULL) {
CU_cleanup_registry();
return CU_get_error();
}
/* Add tests */
if (
CU_add_test(suite, "base64-decode", test_base64_decode) == NULL
|| CU_add_test(suite, "instruction-parse", test_instruction_parse) == NULL
|| CU_add_test(suite, "instruction-read", test_instruction_read) == NULL
|| CU_add_test(suite, "instruction-write", test_instruction_write) == NULL
|| CU_add_test(suite, "nest-write", test_nest_write) == NULL
) {
CU_cleanup_registry();
return CU_get_error();
}
return 0;
}

View File

@ -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 "util_suite.h"
#include <CUnit/Basic.h>
int util_suite_init() {
return 0;
}
int util_suite_cleanup() {
return 0;
}
int register_util_suite() {
/* Add util test suite */
CU_pSuite suite = CU_add_suite("util",
util_suite_init, util_suite_cleanup);
if (suite == NULL) {
CU_cleanup_registry();
return CU_get_error();
}
/* Add tests */
if (
CU_add_test(suite, "guac-pool", test_guac_pool) == NULL
|| CU_add_test(suite, "guac-unicode", test_guac_unicode) == NULL
) {
CU_cleanup_registry();
return CU_get_error();
}
return 0;
}

199
util/generate-test-runner.pl Executable file
View File

@ -0,0 +1,199 @@
#!/usr/bin/perl
#
# 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.
#
#
# generate-test-runner.pl
#
# Generates a test runner for the .c files given on the command line. Each .c
# file may declare any number of tests so long as each test uses CUnit and is
# declared with the following convention:
#
# 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.
#
# Absolutely all tests MUST follow the above convention if they are to be
# picked up by this script. Functions which are not tests MUST NOT follow
# the above convention.
#
use strict;
my $num_tests = 0;
my %test_suites = ();
# Parse all test declarations from given file
while (<>) {
if ((my $suite_name, my $test_name) = m/^void\s+test_(\w+)__(\w+)/) {
$num_tests++;
$test_suites{$suite_name} //= ();
push @{$test_suites{$suite_name}}, $test_name;
}
}
# Bail out if there's nothing to write
if ($num_tests == 0) {
die "No unit tests... :(\n";
}
#
# Common test runner header
#
print <<'END';
/*
* 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 <stdlib.h>
#include <CUnit/TestRun.h>
/**
* The current test number, as required by the TAP format. This value is
* automatically incremented by tap_log_test_completed() after each test is
* run.
*/
int tap_test_number = 1;
/**
* Logs the status of a CUnit test which just completed. This implementation
* logs test completion in TAP format.
*
* @param test
* The CUnit test which just completed.
*
* @param suite
* The CUnit test suite associated with the test.
*
* @param failure
* The head element of the test failure list, or NULL if the test passed.
*/
static void tap_log_test_completed(const CU_pTest test,
const CU_pSuite suite, const CU_pFailureRecord failure) {
/* Log success/failure in TAP format */
if (failure == NULL)
printf("ok %i - [%s] %s: OK\n",
tap_test_number, suite->pName, test->pName);
else
printf("not ok %i - [%s] %s: Assertion failed on %s:%i: %s\n",
tap_test_number, suite->pName, test->pName,
failure->strFileName, failure->uiLineNumber,
failure->strCondition);
tap_test_number++;
}
END
#
# Prototypes for all test functions
#
while ((my $suite_name, my $test_names) = each (%test_suites)) {
print "\n/* Automatically-generated prototypes for the $suite_name suite */\n";
foreach my $test_name (@{ $test_names }) {
print "void test_${suite_name}__${test_name}();\n";
}
}
#
# Beginning of main() function body for test runner
#
print <<"END";
/* Automatically-generated test runner */
int main() {
/* Init CUnit test registry */
if (CU_initialize_registry() != CUE_SUCCESS)
return CU_get_error();
END
#
# Within main(), register each test and its corresponding test suite
#
while ((my $suite_name, my $test_names) = each (%test_suites)) {
print <<" END";
/* Create and register all tests for the $suite_name suite */
CU_pSuite $suite_name = CU_add_suite("$suite_name", NULL, NULL);
if ($suite_name == NULL
END
foreach my $test_name (@{ $test_names }) {
print <<" END";
|| CU_add_test($suite_name, "$test_name", test_${suite_name}__${test_name}) == NULL
END
}
print <<" END";
) goto cleanup;
END
}
#
# End of main() function
#
print <<"END";
/* Force line-buffered output to ensure log messages are visible even if
* a test crashes */
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
/* Write TAP header */
printf("1..$num_tests\\n");
/* Run all tests in all suites */
CU_set_test_complete_handler(tap_log_test_completed);
CU_run_all_tests();
cleanup:
/* Tests complete */
CU_cleanup_registry();
return CU_get_error();
}
END