/* * Copyright (c) 2018 Jiri Svoboda * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Prevent an error from being generated */ #define _REALLY_WANT_STRING_H #include #include #ifndef __clang__ #pragma GCC diagnostic ignored "-Wstringop-truncation" #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif PCUT_INIT; PCUT_TEST_SUITE(string); /** strcpy function */ PCUT_TEST(strcpy) { const char *s = "hello"; char buf[7]; size_t i; char *p; for (i = 0; i < 7; i++) buf[i] = 'X'; p = strcpy(buf, s); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'h'); PCUT_ASSERT_TRUE(buf[1] == 'e'); PCUT_ASSERT_TRUE(buf[2] == 'l'); PCUT_ASSERT_TRUE(buf[3] == 'l'); PCUT_ASSERT_TRUE(buf[4] == 'o'); PCUT_ASSERT_TRUE(buf[5] == '\0'); PCUT_ASSERT_TRUE(buf[6] == 'X'); } /** strncpy function with n == 0 */ PCUT_TEST(strncpy_zero) { const char *s = "hello"; char buf[1]; char *p; buf[0] = 'X'; p = strncpy(buf, s, 0); /* No characters are copied */ PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'X'); } /** strncpy function with string longer than n argument */ PCUT_TEST(strncpy_long) { const char *s = "hello"; char buf[5]; size_t i; char *p; for (i = 0; i < 5; i++) buf[i] = 'X'; p = strncpy(buf, s, 4); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'h'); PCUT_ASSERT_TRUE(buf[1] == 'e'); PCUT_ASSERT_TRUE(buf[2] == 'l'); PCUT_ASSERT_TRUE(buf[3] == 'l'); PCUT_ASSERT_TRUE(buf[4] == 'X'); } /** strncpy function with string containing exactly n characters */ PCUT_TEST(strncpy_just) { const char *s = "hello"; char buf[6]; size_t i; char *p; for (i = 0; i < 6; i++) buf[i] = 'X'; p = strncpy(buf, s, 5); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'h'); PCUT_ASSERT_TRUE(buf[1] == 'e'); PCUT_ASSERT_TRUE(buf[2] == 'l'); PCUT_ASSERT_TRUE(buf[3] == 'l'); PCUT_ASSERT_TRUE(buf[4] == 'o'); PCUT_ASSERT_TRUE(buf[5] == 'X'); } /** strncpy function with string containing exactly n - 1 characters */ PCUT_TEST(strncpy_just_over) { const char *s = "hello"; char buf[7]; size_t i; char *p; for (i = 0; i < 7; i++) buf[i] = 'X'; p = strncpy(buf, s, 6); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'h'); PCUT_ASSERT_TRUE(buf[1] == 'e'); PCUT_ASSERT_TRUE(buf[2] == 'l'); PCUT_ASSERT_TRUE(buf[3] == 'l'); PCUT_ASSERT_TRUE(buf[4] == 'o'); PCUT_ASSERT_TRUE(buf[5] == '\0'); PCUT_ASSERT_TRUE(buf[6] == 'X'); } /** strncpy function with string containing less than n - 1 characters */ PCUT_TEST(strncpy_over) { const char *s = "hello"; char buf[8]; size_t i; char *p; for (i = 0; i < 8; i++) buf[i] = 'X'; p = strncpy(buf, s, 7); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'h'); PCUT_ASSERT_TRUE(buf[1] == 'e'); PCUT_ASSERT_TRUE(buf[2] == 'l'); PCUT_ASSERT_TRUE(buf[3] == 'l'); PCUT_ASSERT_TRUE(buf[4] == 'o'); PCUT_ASSERT_TRUE(buf[5] == '\0'); PCUT_ASSERT_TRUE(buf[6] == '\0'); PCUT_ASSERT_TRUE(buf[7] == 'X'); } /** strcat function */ PCUT_TEST(strcat) { char buf[7]; const char *s = "cde"; size_t i; char *p; buf[0] = 'a'; buf[1] = 'b'; buf[2] = '\0'; for (i = 3; i < 7; i++) buf[i] = 'X'; p = strcat(buf, s); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'a'); PCUT_ASSERT_TRUE(buf[1] == 'b'); PCUT_ASSERT_TRUE(buf[2] == 'c'); PCUT_ASSERT_TRUE(buf[3] == 'd'); PCUT_ASSERT_TRUE(buf[4] == 'e'); PCUT_ASSERT_TRUE(buf[5] == '\0'); PCUT_ASSERT_TRUE(buf[6] == 'X'); } /** strncat function with n == 0 */ PCUT_TEST(strncat_zero) { const char *s = "cde"; char buf[4]; char *p; buf[0] = 'a'; buf[1] = 'b'; buf[2] = '\0'; buf[3] = 'X'; p = strncat(buf, s, 0); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'a'); PCUT_ASSERT_TRUE(buf[1] == 'b'); PCUT_ASSERT_TRUE(buf[2] == '\0'); PCUT_ASSERT_TRUE(buf[3] == 'X'); } /** strncat function with string longer than n argument */ PCUT_TEST(strncat_long) { const char *s = "cde"; char buf[6]; size_t i; char *p; buf[0] = 'a'; buf[1] = 'b'; buf[2] = '\0'; for (i = 3; i < 6; i++) buf[i] = 'X'; p = strncat(buf, s, 2); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'a'); PCUT_ASSERT_TRUE(buf[1] == 'b'); PCUT_ASSERT_TRUE(buf[2] == 'c'); PCUT_ASSERT_TRUE(buf[3] == 'd'); PCUT_ASSERT_TRUE(buf[4] == '\0'); PCUT_ASSERT_TRUE(buf[5] == 'X'); } /** strncat function with string containing exactly n characters */ PCUT_TEST(strncat_just) { const char *s = "cde"; char buf[7]; size_t i; char *p; buf[0] = 'a'; buf[1] = 'b'; buf[2] = '\0'; for (i = 3; i < 7; i++) buf[i] = 'X'; p = strncat(buf, s, 3); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'a'); PCUT_ASSERT_TRUE(buf[1] == 'b'); PCUT_ASSERT_TRUE(buf[2] == 'c'); PCUT_ASSERT_TRUE(buf[3] == 'd'); PCUT_ASSERT_TRUE(buf[4] == 'e'); PCUT_ASSERT_TRUE(buf[5] == '\0'); PCUT_ASSERT_TRUE(buf[6] == 'X'); } /** strncat function with string containing exactly n - 1 characters */ PCUT_TEST(strncat_just_over) { const char *s = "cde"; char buf[7]; size_t i; char *p; buf[0] = 'a'; buf[1] = 'b'; buf[2] = '\0'; for (i = 3; i < 7; i++) buf[i] = 'X'; p = strncat(buf, s, 4); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'a'); PCUT_ASSERT_TRUE(buf[1] == 'b'); PCUT_ASSERT_TRUE(buf[2] == 'c'); PCUT_ASSERT_TRUE(buf[3] == 'd'); PCUT_ASSERT_TRUE(buf[4] == 'e'); PCUT_ASSERT_TRUE(buf[5] == '\0'); PCUT_ASSERT_TRUE(buf[6] == 'X'); } /** strncat function with string containing less than n - 1 characters */ PCUT_TEST(strncat_over) { const char *s = "cde"; char buf[7]; size_t i; char *p; buf[0] = 'a'; buf[1] = 'b'; buf[2] = '\0'; for (i = 3; i < 7; i++) buf[i] = 'X'; p = strncat(buf, s, 5); PCUT_ASSERT_TRUE(p == buf); PCUT_ASSERT_TRUE(buf[0] == 'a'); PCUT_ASSERT_TRUE(buf[1] == 'b'); PCUT_ASSERT_TRUE(buf[2] == 'c'); PCUT_ASSERT_TRUE(buf[3] == 'd'); PCUT_ASSERT_TRUE(buf[4] == 'e'); PCUT_ASSERT_TRUE(buf[5] == '\0'); PCUT_ASSERT_TRUE(buf[6] == 'X'); } /** strcmp function with different characters after terminating null */ PCUT_TEST(strcmp_same) { PCUT_ASSERT_TRUE(strcmp("apples\0#", "apples\0$") == 0); } /** strcmp function with first string less than second */ PCUT_TEST(strcmp_less_than) { PCUT_ASSERT_TRUE(strcmp("apples", "oranges") < 0); } /** strcmp function with first string greater than second */ PCUT_TEST(strcmp_greater_than) { PCUT_ASSERT_TRUE(strcmp("oranges", "apples") > 0); } /* strcmp function with first string a prefix of second string */ PCUT_TEST(strcmp_prefix) { PCUT_ASSERT_TRUE(strcmp("apple", "apples") < 0); } /** strcoll function */ PCUT_TEST(strcoll) { /* Same string with different characters after terminating null */ PCUT_ASSERT_TRUE(strcoll("apples\0#", "apples\0$") == 0); /* First string less than second */ PCUT_ASSERT_TRUE(strcoll("apples", "oranges") < 0); /* First string greater than second */ PCUT_ASSERT_TRUE(strcoll("oranges", "apples") > 0); /* First string is prefix of second */ PCUT_ASSERT_TRUE(strcoll("apple", "apples") < 0); } /** strncmp function with n == 0 */ PCUT_TEST(strncmp_zero) { PCUT_ASSERT_TRUE(strncmp("apple", "orange", 0) == 0); } /** strncmp function with strings differing after n characters */ PCUT_TEST(strncmp_long) { PCUT_ASSERT_TRUE(strncmp("apple", "apricot", 2) == 0); } /** strncmp function with strings differing in (n-1)th character */ PCUT_TEST(strncmp_just) { PCUT_ASSERT_TRUE(strncmp("apple", "apricot", 3) < 0); } /** strncmp function with strings differing before (n-1)th character */ PCUT_TEST(strncmp_over) { PCUT_ASSERT_TRUE(strncmp("dart", "tart", 3) < 0); } /** strxfrm function with null destination to determine size needed */ PCUT_TEST(strxfrm_null) { size_t n; n = strxfrm(NULL, "hello", 0); PCUT_ASSERT_INT_EQUALS(5, n); } /** strxfrm function with string longer than n argument */ PCUT_TEST(strxfrm_long) { const char *s = "hello"; char buf[5]; size_t i; size_t n; for (i = 0; i < 5; i++) buf[i] = 'X'; n = strxfrm(buf, s, 4); PCUT_ASSERT_INT_EQUALS(5, n); PCUT_ASSERT_TRUE(buf[0] == 'h'); PCUT_ASSERT_TRUE(buf[1] == 'e'); PCUT_ASSERT_TRUE(buf[2] == 'l'); PCUT_ASSERT_TRUE(buf[3] == 'l'); PCUT_ASSERT_TRUE(buf[4] == 'X'); } /** strxfrm function with string containing exactly n characters */ PCUT_TEST(strxfrm_just) { const char *s = "hello"; char buf[6]; size_t i; size_t n; for (i = 0; i < 6; i++) buf[i] = 'X'; n = strxfrm(buf, s, 5); PCUT_ASSERT_INT_EQUALS(5, n); PCUT_ASSERT_TRUE(buf[0] == 'h'); PCUT_ASSERT_TRUE(buf[1] == 'e'); PCUT_ASSERT_TRUE(buf[2] == 'l'); PCUT_ASSERT_TRUE(buf[3] == 'l'); PCUT_ASSERT_TRUE(buf[4] == 'o'); PCUT_ASSERT_TRUE(buf[5] == 'X'); } /** strxfrm function with string containing exactly n - 1 characters */ PCUT_TEST(strxfrm_just_over) { const char *s = "hello"; char buf[7]; size_t i; size_t n; for (i = 0; i < 7; i++) buf[i] = 'X'; n = strxfrm(buf, s, 6); PCUT_ASSERT_INT_EQUALS(5, n); PCUT_ASSERT_TRUE(buf[0] == 'h'); PCUT_ASSERT_TRUE(buf[1] == 'e'); PCUT_ASSERT_TRUE(buf[2] == 'l'); PCUT_ASSERT_TRUE(buf[3] == 'l'); PCUT_ASSERT_TRUE(buf[4] == 'o'); PCUT_ASSERT_TRUE(buf[5] == '\0'); PCUT_ASSERT_TRUE(buf[6] == 'X'); } /** strxfrm function with string containing less than n - 1 characters */ PCUT_TEST(strxfrm_over) { const char *s = "hello"; char buf[8]; size_t i; size_t n; for (i = 0; i < 8; i++) buf[i] = 'X'; n = strxfrm(buf, s, 7); PCUT_ASSERT_INT_EQUALS(5, n); PCUT_ASSERT_TRUE(buf[0] == 'h'); PCUT_ASSERT_TRUE(buf[1] == 'e'); PCUT_ASSERT_TRUE(buf[2] == 'l'); PCUT_ASSERT_TRUE(buf[3] == 'l'); PCUT_ASSERT_TRUE(buf[4] == 'o'); PCUT_ASSERT_TRUE(buf[5] == '\0'); PCUT_ASSERT_TRUE(buf[6] == 'X'); PCUT_ASSERT_TRUE(buf[7] == 'X'); } /** strchr function searching for null character */ PCUT_TEST(strchr_nullchar) { const char *s = "abcabc"; char *p; p = strchr(s, '\0'); PCUT_ASSERT_TRUE((const char *)p == &s[6]); } /** strchr function with character occurring in string */ PCUT_TEST(strchr_found) { const char *s = "abcabc"; char *p; p = strchr(s, 'b'); PCUT_ASSERT_TRUE((const char *)p == &s[1]); } /** strchr function with character not occurring in string */ PCUT_TEST(strchr_not_found) { const char *s = "abcabc"; char *p; p = strchr(s, 'd'); PCUT_ASSERT_TRUE(p == NULL); } /** strcspn function with empty search string */ PCUT_TEST(strcspn_empty_str) { size_t n; n = strcspn("", "abc"); PCUT_ASSERT_INT_EQUALS(0, n); } /** strcspn function with empty character set */ PCUT_TEST(strcspn_empty_set) { size_t n; n = strcspn("abc", ""); PCUT_ASSERT_INT_EQUALS(3, n); } /** strcspn function with regular arguments */ PCUT_TEST(strcspn_regular) { size_t n; n = strcspn("baBAba", "AB"); PCUT_ASSERT_INT_EQUALS(2, n); } /** strpbrk function with empty search string */ PCUT_TEST(strpbrk_empty_string) { const char *p; p = strpbrk("", "abc"); PCUT_ASSERT_NULL(p); } /** strpbrk function with empty character set */ PCUT_TEST(strpbrk_empty_set) { const char *p; p = strpbrk("abc", ""); PCUT_ASSERT_NULL(p); } /** strpbrk function with regular parameters */ PCUT_TEST(strpbrk_regular) { const char *s = "baBAba"; char *p; p = strpbrk(s, "ab"); PCUT_ASSERT_TRUE((const char *)p == s); } /** strrchr function searching for null character */ PCUT_TEST(strrchr_nullchar) { const char *s = "abcabc"; char *p; p = strrchr(s, '\0'); PCUT_ASSERT_TRUE((const char *)p == &s[6]); } /** strrchr function with character occurring in string */ PCUT_TEST(strrchr_found) { const char *s = "abcabc"; char *p; p = strrchr(s, 'b'); PCUT_ASSERT_TRUE((const char *)p == &s[4]); } /** strrchr function with character not occurring in string */ PCUT_TEST(strrchr_not_found) { const char *s = "abcabc"; char *p; p = strrchr(s, 'd'); PCUT_ASSERT_TRUE(p == NULL); } /** strspn function with empty search string */ PCUT_TEST(strspn_empty_str) { size_t n; n = strspn("", "abc"); PCUT_ASSERT_INT_EQUALS(0, n); } /** strspn function with empty character set */ PCUT_TEST(strspn_empty_set) { size_t n; n = strspn("abc", ""); PCUT_ASSERT_INT_EQUALS(0, n); } /** strspn function with regular arguments */ PCUT_TEST(strspn_regular) { size_t n; n = strspn("baBAba", "ab"); PCUT_ASSERT_INT_EQUALS(2, n); } /** strstr function looking for empty substring */ PCUT_TEST(strstr_empty) { const char *str = "abcabcabcdabc"; char *p; p = strstr(str, ""); PCUT_ASSERT_TRUE((const char *) p == str); } /** strstr function looking for substring with success */ PCUT_TEST(strstr_found) { const char *str = "abcabcabcdabc"; char *p; p = strstr(str, "abcd"); PCUT_ASSERT_TRUE((const char *) p == &str[6]); } /** strstr function looking for substring with failure */ PCUT_TEST(strstr_notfound) { const char *str = "abcabcabcdabc"; char *p; p = strstr(str, "abcde"); PCUT_ASSERT_NULL(p); } /** strtok function */ PCUT_TEST(strtok) { char str[] = ":a::b;;;$c"; char *t; t = strtok(str, ":"); PCUT_ASSERT_TRUE(t == &str[1]); PCUT_ASSERT_INT_EQUALS(0, strcmp(t, "a")); t = strtok(NULL, ";"); PCUT_ASSERT_TRUE(t == &str[3]); PCUT_ASSERT_INT_EQUALS(0, strcmp(t, ":b")); t = strtok(NULL, "$;"); PCUT_ASSERT_TRUE(t == &str[9]); PCUT_ASSERT_INT_EQUALS(0, strcmp(t, "c")); t = strtok(NULL, "$"); PCUT_ASSERT_NULL(t); } /** strerror function with zero argument */ PCUT_TEST(strerror_zero) { char *p; p = strerror(0); PCUT_ASSERT_NOT_NULL(p); } /** strerror function with errno value argument */ PCUT_TEST(strerror_errno) { char *p; p = strerror(EINVAL); PCUT_ASSERT_NOT_NULL(p); } /** strerror function with negative argument */ PCUT_TEST(strerror_negative) { char *p; p = strerror(-1); PCUT_ASSERT_NOT_NULL(p); } /** strlen function with empty string */ PCUT_TEST(strlen_empty) { PCUT_ASSERT_INT_EQUALS(0, strlen("")); } /** strlen function with non-empty string */ PCUT_TEST(strlen_nonempty) { PCUT_ASSERT_INT_EQUALS(3, strlen("abc")); } /** strlen function with empty string and non-zero limit */ PCUT_TEST(strnlen_empty_short) { PCUT_ASSERT_INT_EQUALS(0, strnlen("", 1)); } /** strlen function with empty string and zero limit */ PCUT_TEST(strnlen_empty_eq) { PCUT_ASSERT_INT_EQUALS(0, strnlen("", 0)); } /** strlen function with non empty string below limit */ PCUT_TEST(strnlen_nonempty_short) { PCUT_ASSERT_INT_EQUALS(3, strnlen("abc", 5)); } /** strlen function with non empty string just below limit */ PCUT_TEST(strnlen_nonempty_just_short) { PCUT_ASSERT_INT_EQUALS(3, strnlen("abc", 4)); } /** strlen function with non empty string of length equal to limit */ PCUT_TEST(strnlen_nonempty_eq) { PCUT_ASSERT_INT_EQUALS(3, strnlen("abc", 3)); } /** strlen function with non empty string of length above limit */ PCUT_TEST(strnlen_nonempty_long) { PCUT_ASSERT_INT_EQUALS(2, strnlen("abc", 2)); } /** strdup function with empty string */ PCUT_TEST(strdup_empty) { char *d = strdup(""); PCUT_ASSERT_NOT_NULL(d); PCUT_ASSERT_TRUE(d[0] == '\0'); free(d); } /** strdup function with non-empty string */ PCUT_TEST(strdup_nonempty) { char *d = strdup("abc"); PCUT_ASSERT_NOT_NULL(d); PCUT_ASSERT_TRUE(d[0] == 'a'); PCUT_ASSERT_TRUE(d[1] == 'b'); PCUT_ASSERT_TRUE(d[2] == 'c'); PCUT_ASSERT_TRUE(d[3] == '\0'); free(d); } /** strndup function with empty string and non-zero limit */ PCUT_TEST(strndup_empty_short) { char *d = strndup("", 1); PCUT_ASSERT_NOT_NULL(d); PCUT_ASSERT_TRUE(d[0] == '\0'); free(d); } /** strndup function with empty string and zero limit */ PCUT_TEST(strndup_empty_eq) { char *d = strndup("", 0); PCUT_ASSERT_NOT_NULL(d); PCUT_ASSERT_TRUE(d[0] == '\0'); free(d); } /** strndup function with non-empty string of length below limit */ PCUT_TEST(strndup_nonempty_short) { #pragma GCC diagnostic push // Intentionally checking it works with _longer_ size than actual #if defined(__GNUC__) && (__GNUC__ >= 11) #pragma GCC diagnostic ignored "-Wstringop-overread" #endif char *d = strndup("abc", 5); #pragma GCC diagnostic pop PCUT_ASSERT_NOT_NULL(d); PCUT_ASSERT_TRUE(d[0] == 'a'); PCUT_ASSERT_TRUE(d[1] == 'b'); PCUT_ASSERT_TRUE(d[2] == 'c'); PCUT_ASSERT_TRUE(d[3] == '\0'); free(d); } /** strndup function with non-empty string of length equal to limit */ PCUT_TEST(strndup_nonempty_eq) { char *d = strndup("abc", 3); PCUT_ASSERT_NOT_NULL(d); PCUT_ASSERT_TRUE(d[0] == 'a'); PCUT_ASSERT_TRUE(d[1] == 'b'); PCUT_ASSERT_TRUE(d[2] == 'c'); PCUT_ASSERT_TRUE(d[3] == '\0'); free(d); } /** strndup function with non-empty string of length above limit */ PCUT_TEST(strndup_nonempty_long) { char *d = strndup("abc", 2); PCUT_ASSERT_NOT_NULL(d); PCUT_ASSERT_TRUE(d[0] == 'a'); PCUT_ASSERT_TRUE(d[1] == 'b'); PCUT_ASSERT_TRUE(d[2] == '\0'); free(d); } PCUT_EXPORT(string);