diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index eb59768e..e2af6595 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -19,6 +19,7 @@ set(LIBSSH_UNIT_TESTS torture_temp_file torture_push_pop_dir torture_session_keys + torture_string torture_tokens ) diff --git a/tests/unittests/torture_string.c b/tests/unittests/torture_string.c new file mode 100644 index 00000000..254444ab --- /dev/null +++ b/tests/unittests/torture_string.c @@ -0,0 +1,268 @@ +/* + * torture_string.c - torture tests for ssh_string functions + * + * This file is part of the SSH Library + * + * Copyright (c) 2025 Praneeth Sarode + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#define LIBSSH_STATIC + +#include "libssh/string.h" +#include "string.c" +#include "torture.h" + +static void torture_ssh_string_new(void **state) +{ + struct ssh_string_struct *str = NULL; + + (void)state; + + /* Test normal allocation */ + str = ssh_string_new(100); + assert_non_null(str); + assert_int_equal(ssh_string_len(str), 100); + ssh_string_free(str); + + /* Test zero size */ + str = ssh_string_new(0); + assert_non_null(str); + assert_int_equal(ssh_string_len(str), 0); + ssh_string_free(str); + + /* Test maximum size */ + str = ssh_string_new(STRING_SIZE_MAX - 1); + assert_non_null(str); + assert_int_equal(ssh_string_len(str), STRING_SIZE_MAX - 1); + ssh_string_free(str); + + /* Test size too large - should fail */ + str = ssh_string_new(STRING_SIZE_MAX + 1); + assert_null(str); + assert_int_equal(errno, EINVAL); +} + +static void torture_ssh_string_from_char(void **state) +{ + struct ssh_string_struct *str = NULL; + const char *test_string = "Hello, World!"; + const char *empty_string = ""; + + (void)state; + + /* Test normal string */ + str = ssh_string_from_char(test_string); + assert_non_null(str); + assert_int_equal(ssh_string_len(str), strlen(test_string)); + assert_memory_equal(ssh_string_data(str), test_string, strlen(test_string)); + ssh_string_free(str); + + /* Test empty string */ + str = ssh_string_from_char(empty_string); + assert_non_null(str); + assert_int_equal(ssh_string_len(str), 0); + ssh_string_free(str); + + /* Test NULL input */ + str = ssh_string_from_char(NULL); + assert_null(str); + assert_int_equal(errno, EINVAL); +} + +static void torture_ssh_string_fill(void **state) +{ + struct ssh_string_struct *str = NULL; + const char *test_data = "Test data"; + int rc; + + (void)state; + + /* Test normal fill */ + str = ssh_string_new(20); + assert_non_null(str); + + rc = ssh_string_fill(str, test_data, strlen(test_data)); + assert_int_equal(rc, 0); + assert_memory_equal(ssh_string_data(str), test_data, strlen(test_data)); + ssh_string_free(str); + + /* Test fill with exact size */ + str = ssh_string_new(strlen(test_data)); + assert_non_null(str); + + rc = ssh_string_fill(str, test_data, strlen(test_data)); + assert_int_equal(rc, 0); + ssh_string_free(str); + + /* Test NULL data */ + str = ssh_string_new(10); + assert_non_null(str); + + rc = ssh_string_fill(str, NULL, 5); + assert_int_equal(rc, -1); + ssh_string_free(str); + + /* Test zero length */ + str = ssh_string_new(10); + assert_non_null(str); + + rc = ssh_string_fill(str, test_data, 0); + assert_int_equal(rc, -1); + ssh_string_free(str); +} + +static void torture_ssh_string_to_char(void **state) +{ + struct ssh_string_struct *str = NULL; + const char *test_string = "Convert to char"; + char *result = NULL; + + (void)state; + + /* Test normal string */ + str = ssh_string_from_char(test_string); + assert_non_null(str); + + result = ssh_string_to_char(str); + assert_non_null(result); + assert_string_equal(result, test_string); + + ssh_string_free_char(result); + ssh_string_free(str); + + /* Test empty string */ + str = ssh_string_from_char(""); + assert_non_null(str); + + result = ssh_string_to_char(str); + assert_non_null(result); + assert_string_equal(result, ""); + + ssh_string_free_char(result); + ssh_string_free(str); + + /* Test NULL string */ + result = ssh_string_to_char(NULL); + assert_null(result); +} + +static void torture_ssh_string_copy(void **state) +{ + struct ssh_string_struct *str = NULL, *copy = NULL; + const char *test_string = "Copy me!"; + + (void)state; + + /* Test normal copy */ + str = ssh_string_from_char(test_string); + assert_non_null(str); + + copy = ssh_string_copy(str); + assert_non_null(copy); + assert_int_equal(ssh_string_len(copy), ssh_string_len(str)); + assert_memory_equal(ssh_string_data(copy), + ssh_string_data(str), + ssh_string_len(str)); + + /* Ensure they are different objects */ + assert_ptr_not_equal(str, copy); + assert_ptr_not_equal(ssh_string_data(str), ssh_string_data(copy)); + + ssh_string_free(str); + ssh_string_free(copy); + + /* Test copy of empty string */ + str = ssh_string_from_char(""); + assert_non_null(str); + + copy = ssh_string_copy(str); + assert_non_null(copy); + assert_int_equal(ssh_string_len(copy), 0); + + ssh_string_free(str); + ssh_string_free(copy); + + /* Test NULL string */ + copy = ssh_string_copy(NULL); + assert_null(copy); +} + +static void torture_ssh_string_burn(void **state) +{ + struct ssh_string_struct *str = NULL; + const char *test_string = "Secret data"; + void *data = NULL; + size_t len; + int i; + + (void)state; + + /* Test burning a string */ + str = ssh_string_from_char(test_string); + assert_non_null(str); + + data = ssh_string_data(str); + len = ssh_string_len(str); + + /* Verify data is there initially */ + assert_memory_equal(data, test_string, len); + + /* Burn the string */ + ssh_string_burn(str); + + /* Verify data is zeroed out */ + for (i = 0; i < (int)len; i++) { + assert_int_equal(((unsigned char *)data)[i], 0); + } + + ssh_string_free(str); + + /* Test burning NULL string (should not crash) */ + ssh_string_burn(NULL); + + /* Test burning zero-size string */ + str = ssh_string_new(0); + assert_non_null(str); + ssh_string_burn(str); + ssh_string_free(str); +} + +int torture_run_tests(void) +{ + int rc; + struct CMUnitTest tests[] = { + cmocka_unit_test(torture_ssh_string_new), + cmocka_unit_test(torture_ssh_string_from_char), + cmocka_unit_test(torture_ssh_string_fill), + cmocka_unit_test(torture_ssh_string_to_char), + cmocka_unit_test(torture_ssh_string_copy), + cmocka_unit_test(torture_ssh_string_burn), + }; + + ssh_init(); + torture_filter_tests(tests); + rc = cmocka_run_group_tests(tests, NULL, NULL); + ssh_finalize(); + + return rc; +}