From 464c94501dc8d602958153d70279e6beadc90edd Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 1 Mar 2014 21:31:52 -0800 Subject: [PATCH] Add string utility functions and unit tests. --- src/common/Makefile.am | 8 ++-- src/common/guac_string.c | 93 +++++++++++++++++++++++++++++++++++++ src/common/guac_string.h | 50 ++++++++++++++++++++ tests/Makefile.am | 7 ++- tests/common/common_suite.c | 56 ++++++++++++++++++++++ tests/common/common_suite.h | 48 +++++++++++++++++++ tests/common/guac_string.c | 73 +++++++++++++++++++++++++++++ tests/test_libguac.c | 2 + 8 files changed, 332 insertions(+), 5 deletions(-) create mode 100644 src/common/guac_string.c create mode 100644 src/common/guac_string.h create mode 100644 tests/common/common_suite.c create mode 100644 tests/common/common_suite.h create mode 100644 tests/common/guac_string.c diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 4fc272ed..958bb54a 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -28,15 +28,17 @@ noinst_LTLIBRARIES = libguac_common.la noinst_HEADERS = \ guac_io.h \ - guac_dot_cursor.c \ + guac_dot_cursor.h \ guac_list.h \ - guac_pointer_cursor.c + guac_pointer_cursor.h \ + guac_string.h libguac_common_la_SOURCES = \ guac_io.c \ guac_dot_cursor.c \ guac_list.c \ - guac_pointer_cursor.c + guac_pointer_cursor.c \ + guac_string.c libguac_common_la_LIBADD = @LIBGUAC_LTLIB@ diff --git a/src/common/guac_string.c b/src/common/guac_string.c new file mode 100644 index 00000000..fa92b248 --- /dev/null +++ b/src/common/guac_string.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "config.h" + +#include "guac_string.h" + +#include +#include + +int guac_count_occurrences(const char* string, char c) { + + int count = 0; + + while (*string != 0) { + + /* Count each occurrence */ + if (*string == c) + count++; + + /* Next character */ + string++; + + } + + return count; + +} + +char** guac_split(const char* string, char delim) { + + int i = 0; + + int token_count = guac_count_occurrences(string, delim) + 1; + const char* token_start = string; + + /* Allocate space for tokens */ + char** tokens = malloc(sizeof(char*) * (token_count+1)); + + do { + + int length; + char* token; + + /* Find end of token */ + while (*string != 0 && *string != delim) + string++; + + /* Calculate token length */ + length = string - token_start; + + /* Allocate space for token and NULL terminator */ + tokens[i++] = token = malloc(length + 1); + + /* Copy token, store null */ + memcpy(token, token_start, length); + token[length] = 0; + + /* Stop at end of string */ + if (*string == 0) + break; + + /* Next token */ + token_start = ++string; + + } while (i < token_count); + + /* NULL terminator */ + tokens[i] = NULL; + + return tokens; + +} + diff --git a/src/common/guac_string.h b/src/common/guac_string.h new file mode 100644 index 00000000..9a58f151 --- /dev/null +++ b/src/common/guac_string.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __GUAC_COMMON_STRING_H +#define __GUAC_COMMON_STRING_H + +#include "config.h" + +/** + * Counts the number of occurrences of a given character in a string. + * + * @param string The string to count occurrences within. + * @param c The character to count occurrences of. + * @return The number of occurrences. + */ +int guac_count_occurrences(const char* string, char c); + +/** + * Splits a string into a newly-allocated array of strings. The array itself + * and each string within the array will eventually need to be freed. The array + * is NULL-terminated. + * + * @param string The string to split. + * @param delim The character which separates individual substrings within the + * given string. + * @return A newly-allocated, NULL-terminated array of strings. + */ +char** guac_split(const char* string, char delim); + +#endif + diff --git a/tests/Makefile.am b/tests/Makefile.am index 0d153dd8..56a51b09 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,13 +22,14 @@ AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 -AM_CFLAGS = -Werror -Wall -pedantic @LIBGUAC_INCLUDE@ +AM_CFLAGS = -Werror -Wall -pedantic @LIBGUAC_INCLUDE@ @COMMON_INCLUDE@ TESTS = test_libguac check_PROGRAMS = test_libguac noinst_HEADERS = \ client/client_suite.h \ + common/common_suite.h \ protocol/suite.h \ util/util_suite.h @@ -37,6 +38,8 @@ test_libguac_SOURCES = \ client/client_suite.c \ client/buffer_pool.c \ client/layer_pool.c \ + common/common_suite.c \ + common/guac_string.c \ protocol/suite.c \ protocol/base64_decode.c \ protocol/instruction_parse.c \ @@ -47,5 +50,5 @@ test_libguac_SOURCES = \ util/guac_pool.c \ util/guac_unicode.c -test_libguac_LDADD = @LIBGUAC_LTLIB@ @CUNIT_LIBS@ +test_libguac_LDADD = @LIBGUAC_LTLIB@ @CUNIT_LIBS@ @COMMON_LTLIB@ diff --git a/tests/common/common_suite.c b/tests/common/common_suite.c new file mode 100644 index 00000000..409df4eb --- /dev/null +++ b/tests/common/common_suite.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "config.h" + +#include "common_suite.h" + +#include + +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-string", test_guac_string) == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + return 0; + +} + diff --git a/tests/common/common_suite.h b/tests/common/common_suite.h new file mode 100644 index 00000000..4a039be5 --- /dev/null +++ b/tests/common/common_suite.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef _GUAC_TEST_COMMON_SUITE_H +#define _GUAC_TEST_COMMON_SUITE_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 + */ + +#include "config.h" + +/** + * Registers the common test suite with CUnit. + */ +int register_common_suite(); + +/** + * Unit test for string utility functions. + */ +void test_guac_string(); + +#endif + diff --git a/tests/common/guac_string.c b/tests/common/guac_string.c new file mode 100644 index 00000000..3deb1abc --- /dev/null +++ b/tests/common/guac_string.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "config.h" + +#include "common_suite.h" +#include "guac_string.h" + +#include +#include + +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')); + + /* Split test string */ + 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); + +} + diff --git a/tests/test_libguac.c b/tests/test_libguac.c index ad6b5889..b1cfd1ac 100644 --- a/tests/test_libguac.c +++ b/tests/test_libguac.c @@ -23,6 +23,7 @@ #include "config.h" #include "client/client_suite.h" +#include "common/common_suite.h" #include "protocol/suite.h" #include "util/util_suite.h" @@ -38,6 +39,7 @@ int main() { register_protocol_suite(); register_client_suite(); register_util_suite(); + register_common_suite(); /* Run tests */ CU_basic_set_mode(CU_BRM_VERBOSE);