blob: 2e16f97291cd6bbfbb13dd61eaca0ddc868155eb [file] [log] [blame]
/* libnih
*
* test_string.c - test suite for nih/string.c
*
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>.
* Copyright © 2009 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <nih/test.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pty.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <nih/macros.h>
#include <nih/alloc.h>
#include <nih/string.h>
void
test_sprintf (void)
{
char *str1, *str2;
TEST_FUNCTION ("nih_sprintf");
/* Check that we can create a formatted string with no parent,
* it should be allocated with nih_alloc and be the right length.
*/
TEST_FEATURE ("with no parent");
TEST_ALLOC_FAIL {
str1 = nih_sprintf (NULL, "this %s a test %d", "is", 54321);
if (test_alloc_failed) {
TEST_EQ_P (str1, NULL);
continue;
}
TEST_ALLOC_ORPHAN (str1);
TEST_ALLOC_SIZE (str1, strlen (str1) + 1);
TEST_EQ_STR (str1, "this is a test 54321");
nih_free (str1);
}
/* Check that we can create a string with a parent. */
TEST_FEATURE ("with a parent");
str1 = nih_sprintf (NULL, "this %s a test %d", "is", 54321);
TEST_ALLOC_FAIL {
str2 = nih_sprintf (str1, "another %d test %s",
12345, "string");
if (test_alloc_failed) {
TEST_EQ_P (str2, NULL);
continue;
}
TEST_ALLOC_PARENT (str2, str1);
TEST_ALLOC_SIZE (str2, strlen (str2) + 1);
TEST_EQ_STR (str2, "another 12345 test string");
nih_free (str2);
}
nih_free (str1);
}
static char *
my_vsprintf (void *parent,
const char *format,
...)
{
char *str;
va_list args;
va_start (args, format);
str = nih_vsprintf (parent, format, args);
va_end (args);
return str;
}
void
test_vsprintf (void)
{
char *str1, *str2;
TEST_FUNCTION ("nih_vsprintf");
/* Check that we can create a formatted string for a va_list,
* first with no parent.
*/
TEST_FEATURE ("with no parent");
TEST_ALLOC_FAIL {
str1 = my_vsprintf (NULL, "this %s a test %d", "is", 54321);
if (test_alloc_failed) {
TEST_EQ_P (str1, NULL);
continue;
}
TEST_ALLOC_ORPHAN (str1);
TEST_ALLOC_SIZE (str1, strlen (str1) + 1);
TEST_EQ_STR (str1, "this is a test 54321");
nih_free (str1);
}
/* And then with a parent. */
TEST_FEATURE ("with a parent");
str1 = my_vsprintf (NULL, "this %s a test %d", "is", 54321);
TEST_ALLOC_FAIL {
str2 = my_vsprintf (str1, "another %d test %s",
12345, "string");
if (test_alloc_failed) {
TEST_EQ_P (str2, NULL);
continue;
}
TEST_ALLOC_PARENT (str2, str1);
TEST_ALLOC_SIZE (str2, strlen (str2) + 1);
TEST_EQ_STR (str2, "another 12345 test string");
nih_free (str2);
}
nih_free (str1);
}
void
test_strdup (void)
{
char *str1, *str2;
TEST_FUNCTION ("nih_strdup");
/* Check that we can create a duplicate of another string,
* allocated with nih_alloc and no parent.
*/
TEST_FEATURE ("with no parent");
TEST_ALLOC_FAIL {
str1 = nih_strdup (NULL, "this is a test");
if (test_alloc_failed) {
TEST_EQ_P (str1, NULL);
continue;
}
TEST_ALLOC_ORPHAN (str1);
TEST_ALLOC_SIZE (str1, strlen (str1) + 1);
TEST_EQ_STR (str1, "this is a test");
nih_free (str1);
}
/* And check we can allocate with a parent. */
TEST_FEATURE ("with a parent");
str1 = nih_strdup (NULL, "this is a test");
TEST_ALLOC_FAIL {
str2 = nih_strdup (str1, "another test string");
if (test_alloc_failed) {
TEST_EQ_P (str2, NULL);
continue;
}
TEST_ALLOC_PARENT (str2, str1);
TEST_ALLOC_SIZE (str2, strlen (str2) + 1);
TEST_EQ_STR (str2, "another test string");
nih_free (str2);
}
nih_free (str1);
}
void
test_strndup (void)
{
char *str1, *str2;
TEST_FUNCTION ("nih_strndup");
/* Check that we can create a duplicate of the first portion of
* another string, allocated with nih_alloc and no parent. The
* new string should still include a NULL byte.
*/
TEST_FEATURE ("with no parent");
TEST_ALLOC_FAIL {
str1 = nih_strndup (NULL, "this is a test", 7);
if (test_alloc_failed) {
TEST_EQ_P (str1, NULL);
continue;
}
TEST_ALLOC_ORPHAN (str1);
TEST_ALLOC_SIZE (str1, 8);
TEST_EQ_STR (str1, "this is");
nih_free (str1);
}
/* Check that it works with a parent. */
TEST_FEATURE ("with a parent");
str1 = nih_strndup (NULL, "this is a test", 7);
TEST_ALLOC_FAIL {
str2 = nih_strndup (str1, "another test string", 12);
if (test_alloc_failed) {
TEST_EQ_P (str2, NULL);
continue;
}
TEST_ALLOC_PARENT (str2, str1);
TEST_ALLOC_SIZE (str2, 13);
TEST_EQ_STR (str2, "another test");
nih_free (str2);
}
nih_free (str1);
/* Check that the right thing happens if the length we give is
* longer than the string, the returned size should be ample but
* with the complete string copied in.
*/
TEST_FEATURE ("with larger length than string");
TEST_ALLOC_FAIL {
str1 = nih_strndup (NULL, "small string", 20);
if (test_alloc_failed) {
TEST_EQ_P (str1, NULL);
continue;
}
TEST_ALLOC_SIZE (str1, 21);
TEST_EQ_STR (str1, "small string");
nih_free (str1);
}
}
void
test_strcat (void)
{
char *str, *ret;
TEST_FUNCTION ("nih_strcat");
/* Check that we can extend a string with another, resulting in the
* original string being modified and the new pointer stored in the
* argument and returned.
*/
TEST_FEATURE ("with string");
TEST_ALLOC_FAIL {
char *tmp;
TEST_ALLOC_SAFE {
str = nih_strdup (NULL, "this is a test");
}
tmp = str;
ret = nih_strcat (&str, NULL, " of strdup");
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (str, tmp);
TEST_EQ_STR (str, "this is a test");
nih_free (str);
continue;
}
TEST_NE (ret, NULL);
TEST_EQ_P (ret, str);
TEST_ALLOC_SIZE (str, 25);
TEST_EQ_STR (str, "this is a test of strdup");
nih_free (str);
}
/* Check that when no string is passed, this behaves as strdup.
*/
TEST_FEATURE ("with NULL");
TEST_ALLOC_FAIL {
str = NULL;
ret = nih_strcat (&str, NULL, "test of strdup");
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (str, NULL);
continue;
}
TEST_NE (ret, NULL);
TEST_EQ_P (ret, str);
TEST_ALLOC_SIZE (str, 15);
TEST_EQ_STR (str, "test of strdup");
nih_free (str);
}
}
void
test_strncat (void)
{
char *str, *ret;
TEST_FUNCTION ("nih_strncat");
/* Check that we can extend a string with the first number of bytes
* from another, resulting in the original string being modified and
* the new pointer stored in the argument and returned.
*/
TEST_FEATURE ("with larger string than length");
TEST_ALLOC_FAIL {
char *tmp;
TEST_ALLOC_SAFE {
str = nih_strdup (NULL, "this is a test");
}
tmp = str;
ret = nih_strncat (&str, NULL, " of strndup", 3);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (str, tmp);
TEST_EQ_STR (str, "this is a test");
nih_free (str);
continue;
}
TEST_NE (ret, NULL);
TEST_EQ_P (ret, str);
TEST_ALLOC_SIZE (str, 18);
TEST_EQ_STR (str, "this is a test of");
nih_free (str);
}
/* Check that if a longer length than the string is given, enough
* space is reserved but the string copy stops at the NULL.
*/
TEST_FEATURE ("with larger length than string");
TEST_ALLOC_FAIL {
char *tmp;
TEST_ALLOC_SAFE {
str = nih_strdup (NULL, "this is a test");
}
tmp = str;
ret = nih_strncat (&str, NULL, " of strndup", 21);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (str, tmp);
TEST_EQ_STR (str, "this is a test");
nih_free (str);
continue;
}
TEST_NE (ret, NULL);
TEST_EQ_P (ret, str);
TEST_ALLOC_SIZE (str, 36);
TEST_EQ_STR (str, "this is a test of strndup");
nih_free (str);
}
/* Check that when no string is passed, this behaves as strndup.
*/
TEST_FEATURE ("with NULL");
TEST_ALLOC_FAIL {
str = NULL;
ret = nih_strncat (&str, NULL, "test of strndup", 12);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (str, NULL);
continue;
}
TEST_NE (ret, NULL);
TEST_EQ_P (ret, str);
TEST_ALLOC_SIZE (str, 13);
TEST_EQ_STR (str, "test of strn");
nih_free (str);
}
}
void
test_strcat_sprintf (void)
{
char *str, *ret;
TEST_FUNCTION ("test_strcat_sprintf");
/* Check that we can extend a string with a formatted string,
* resulting in the original string being modified and the new
* pointer stored in the argument and returned.
*/
TEST_FEATURE ("with original string");
TEST_ALLOC_FAIL {
char *tmp;
TEST_ALLOC_SAFE {
str = nih_strdup (NULL, "this");
}
tmp = str;
ret = nih_strcat_sprintf (&str, NULL,
" %s a test %d", "is", 54321);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (str, tmp);
TEST_EQ_STR (str, "this");
nih_free (str);
continue;
}
TEST_NE (ret, NULL);
TEST_EQ_P (ret, str);
TEST_ALLOC_SIZE (str, 21);
TEST_EQ_STR (str, "this is a test 54321");
nih_free (str);
}
/* Check that when no string is passed, this behaves as sprintf.
*/
TEST_FEATURE ("with NULL");
TEST_ALLOC_FAIL {
str = NULL;
ret = nih_strcat_sprintf (&str, NULL,
"%s a test %d", "is", 54321);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (str, NULL);
continue;
}
TEST_NE (ret, NULL);
TEST_EQ_P (ret, str);
TEST_ALLOC_SIZE (str, 15);
TEST_EQ_STR (str, "is a test 54321");
nih_free (str);
}
}
static char *
my_strcat_vsprintf (char **str,
const void *parent,
const char *format,
...)
{
char *ret;
va_list args;
va_start (args, format);
ret = nih_strcat_vsprintf (str, parent, format, args);
va_end (args);
return ret;
}
void
test_strcat_vsprintf (void)
{
char *str, *ret;
TEST_FUNCTION ("test_strcat_vsprintf");
/* Check that we can extend a string with a formatted string,
* resulting in the original string being modified and the new
* pointer stored in the argument and returned.
*/
TEST_FEATURE ("with original string");
TEST_ALLOC_FAIL {
char *tmp;
TEST_ALLOC_SAFE {
str = nih_strdup (NULL, "this");
}
tmp = str;
ret = my_strcat_vsprintf (&str, NULL,
" %s a test %d", "is", 54321);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (str, tmp);
TEST_EQ_STR (str, "this");
nih_free (str);
continue;
}
TEST_NE (ret, NULL);
TEST_EQ_P (ret, str);
TEST_ALLOC_SIZE (str, 21);
TEST_EQ_STR (str, "this is a test 54321");
nih_free (str);
}
/* Check that when no string is passed, this behaves as sprintf.
*/
TEST_FEATURE ("with NULL");
TEST_ALLOC_FAIL {
str = NULL;
ret = my_strcat_vsprintf (&str, NULL,
"%s a test %d", "is", 54321);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (str, NULL);
continue;
}
TEST_NE (ret, NULL);
TEST_EQ_P (ret, str);
TEST_ALLOC_SIZE (str, 15);
TEST_EQ_STR (str, "is a test 54321");
nih_free (str);
}
}
void
test_str_split (void)
{
char **array;
int i;
TEST_FUNCTION ("nih_str_split");
/* Check that we can split a string into a NULL-terminated array
* at each matching character. The array should be allocated with
* nih_alloc, and each element should also be with the array as
* their parent.
*/
TEST_FEATURE ("with no repeat");
TEST_ALLOC_FAIL {
array = nih_str_split (NULL, "this is a\ttest", " \t", FALSE);
if (test_alloc_failed) {
TEST_EQ_P (array, NULL);
continue;
}
TEST_ALLOC_SIZE (array, sizeof (char *) * 6);
for (i = 0; i < 5; i++)
TEST_ALLOC_PARENT (array[i], array);
TEST_EQ_STR (array[0], "this");
TEST_EQ_STR (array[1], "is");
TEST_EQ_STR (array[2], "");
TEST_EQ_STR (array[3], "a");
TEST_EQ_STR (array[4], "test");
TEST_EQ_P (array[5], NULL);
nih_free (array);
}
/* Check that we can split a string treating multiple consecutive
* matching characters as a single separator to be skipped.
*/
TEST_FEATURE ("with repeat");
TEST_ALLOC_FAIL {
array = nih_str_split (NULL, "this is a\ttest", " \t", TRUE);
if (test_alloc_failed) {
TEST_EQ_P (array, NULL);
continue;
}
TEST_ALLOC_SIZE (array, sizeof (char *) * 5);
for (i = 0; i < 4; i++)
TEST_ALLOC_PARENT (array[i], array);
TEST_EQ_STR (array[0], "this");
TEST_EQ_STR (array[1], "is");
TEST_EQ_STR (array[2], "a");
TEST_EQ_STR (array[3], "test");
TEST_EQ_P (array[4], NULL);
nih_free (array);
}
/* Check that we can give an empty string, and end up with a
* one-element array that only contains a NULL pointer.
*/
TEST_FEATURE ("with empty string");
TEST_ALLOC_FAIL {
array = nih_str_split (NULL, "", " ", FALSE);
if (test_alloc_failed) {
TEST_EQ_P (array, NULL);
continue;
}
TEST_ALLOC_SIZE (array, sizeof (char *));
TEST_EQ_P (array[0], NULL);
nih_free (array);
}
/* Check that we can give a string with only repeating
* delimiters, enable repeat, and we end up with a one-element
* array that only contains a NULL pointer.
*/
TEST_FEATURE ("with empty string except for delimiters");
TEST_ALLOC_FAIL {
array = nih_str_split (NULL, " ", " ", TRUE);
if (test_alloc_failed) {
TEST_EQ_P (array, NULL);
continue;
}
TEST_ALLOC_SIZE (array, sizeof (char *));
TEST_EQ_P (array[0], NULL);
nih_free (array);
}
}
void
test_array_new (void)
{
char **array;
/* Check that we can allocate a NULL-terminated array of strings using
* nih_alloc().
*/
TEST_FUNCTION ("nih_str_array_new");
TEST_ALLOC_FAIL {
array = nih_str_array_new (NULL);
if (test_alloc_failed) {
TEST_EQ_P (array, NULL);
continue;
}
TEST_ALLOC_SIZE (array, sizeof (char *));
TEST_EQ_P (array[0], NULL);
nih_free (array);
}
}
void
test_array_add (void)
{
char **array, **ret;
size_t len;
/* Check that we can append strings to a NULL-terminated array.
*/
TEST_FUNCTION ("nih_str_array_add");
array = nih_str_array_new (NULL);
len = 0;
TEST_ALLOC_FAIL {
ret = nih_str_array_add (&array, NULL, &len, "test");
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ (len, 1);
TEST_EQ_STR (array[0], "test");
TEST_EQ_P (array[1], NULL);
continue;
}
TEST_NE_P (ret, NULL);
TEST_EQ (len, 1);
TEST_ALLOC_PARENT (array[0], array);
TEST_ALLOC_SIZE (array[0], 5);
TEST_EQ_STR (array[0], "test");
TEST_EQ_P (array[1], NULL);
}
nih_free (array);
}
void
test_array_addn (void)
{
char **array, **ret;
size_t len;
/* Check that we can append strings to a NULL-terminated array.
*/
TEST_FUNCTION ("nih_str_array_addn");
array = nih_str_array_new (NULL);
len = 0;
TEST_ALLOC_FAIL {
ret = nih_str_array_addn (&array, NULL, &len, "testing", 4);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ (len, 1);
TEST_EQ_STR (array[0], "test");
TEST_EQ_P (array[1], NULL);
continue;
}
TEST_NE_P (ret, NULL);
TEST_EQ (len, 1);
TEST_ALLOC_PARENT (array[0], array);
TEST_ALLOC_SIZE (array[0], 5);
TEST_EQ_STR (array[0], "test");
TEST_EQ_P (array[1], NULL);
}
nih_free (array);
}
void
test_array_addp (void)
{
char **array, **ret;
char *ptr1, *ptr2;
size_t len;
TEST_FUNCTION ("nih_str_array_addn");
/* Check that we can call the function with a NULL array pointer,
* and get one allocated automatically.
*/
TEST_FEATURE ("with no array given");
ptr1 = nih_alloc (NULL, 1024);
memset (ptr1, ' ', 1024);
TEST_ALLOC_FAIL {
array = NULL;
len = 0;
ret = nih_str_array_addp (&array, NULL, &len, ptr1);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ (len, 0);
continue;
}
TEST_NE_P (ret, NULL);
TEST_EQ (len, 1);
TEST_EQ_P (array[0], ptr1);
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_P (array[1], NULL);
nih_free (array);
}
/* Check that we can append allocated blocks to a
* NULL-terminated array, and that the blocks are automatically
* reparented.
*/
TEST_FEATURE ("with length given");
array = nih_str_array_new (NULL);
len = 0;
ptr1 = nih_alloc (NULL, 1024);
memset (ptr1, ' ', 1024);
TEST_ALLOC_FAIL {
ret = nih_str_array_addp (&array, NULL, &len, ptr1);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ (len, 1);
TEST_EQ_P (array[0], ptr1);
TEST_EQ_P (array[1], NULL);
continue;
}
TEST_NE_P (ret, NULL);
TEST_EQ (len, 1);
TEST_EQ_P (array[0], ptr1);
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_P (array[1], NULL);
}
/* Check that we can omit the length, and have it calculated. */
TEST_FEATURE ("with no length given");
ptr2 = nih_alloc (NULL, 512);
memset (ptr2, ' ', 512);
TEST_ALLOC_FAIL {
ret = nih_str_array_addp (&array, NULL, NULL, ptr2);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (array[0], ptr1);
TEST_EQ_P (array[1], ptr2);
TEST_EQ_P (array[2], NULL);
continue;
}
TEST_NE_P (ret, NULL);
TEST_EQ_P (array[0], ptr1);
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_P (array[1], ptr2);
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_P (array[2], NULL);
}
nih_free (array);
}
void
test_array_copy (void)
{
char **array, **args;
size_t len;
TEST_FUNCTION ("nih_str_array_copy");
args = NIH_MUST (nih_str_array_new (NULL));
NIH_MUST (nih_str_array_add (&args, NULL, NULL, "this"));
NIH_MUST (nih_str_array_add (&args, NULL, NULL, "is"));
NIH_MUST (nih_str_array_add (&args, NULL, NULL, "a"));
NIH_MUST (nih_str_array_add (&args, NULL, NULL, "test"));
/* Check that we can make a copy of an array, with each element
* a copy of the last.
*/
TEST_FEATURE ("with length given");
TEST_ALLOC_FAIL {
len = 0;
array = nih_str_array_copy (NULL, &len, args);
if (test_alloc_failed) {
TEST_EQ_P (array, NULL);
continue;
}
TEST_NE_P (array, NULL);
TEST_EQ (len, 4);
TEST_EQ_STR (array[0], "this");
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_STR (array[1], "is");
TEST_ALLOC_PARENT (array[1], array);
TEST_EQ_STR (array[2], "a");
TEST_ALLOC_PARENT (array[2], array);
TEST_EQ_STR (array[3], "test");
TEST_ALLOC_PARENT (array[3], array);
TEST_EQ_P (array[4], NULL);
nih_free (array);
}
/* Check that we can omit the length, and have it calculated. */
TEST_FEATURE ("with no length given");
TEST_ALLOC_FAIL {
array = nih_str_array_copy (NULL, NULL, args);
if (test_alloc_failed) {
TEST_EQ_P (array, NULL);
continue;
}
TEST_NE_P (array, NULL);
TEST_EQ_STR (array[0], "this");
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_STR (array[1], "is");
TEST_ALLOC_PARENT (array[1], array);
TEST_EQ_STR (array[2], "a");
TEST_ALLOC_PARENT (array[2], array);
TEST_EQ_STR (array[3], "test");
TEST_ALLOC_PARENT (array[3], array);
TEST_EQ_P (array[4], NULL);
nih_free (array);
}
nih_free (args);
/* Check that we can make a copy of an array with a single NULL
* element and have the same returned.
*/
TEST_FEATURE ("with zero-length array");
args = NIH_MUST (nih_str_array_new (NULL));
TEST_ALLOC_FAIL {
len = 0;
array = nih_str_array_copy (NULL, &len, args);
if (test_alloc_failed) {
TEST_EQ_P (array, NULL);
continue;
}
TEST_NE_P (array, NULL);
TEST_EQ (len, 0);
TEST_EQ_P (array[0], NULL);
nih_free (array);
}
nih_free (args);
}
void
test_array_append (void)
{
char **array, **args, **ret;
size_t len;
TEST_FUNCTION ("nih_str_array_append");
args = NIH_MUST (nih_str_array_new (NULL));
NIH_MUST (nih_str_array_add (&args, NULL, NULL, "this"));
NIH_MUST (nih_str_array_add (&args, NULL, NULL, "is"));
NIH_MUST (nih_str_array_add (&args, NULL, NULL, "a"));
NIH_MUST (nih_str_array_add (&args, NULL, NULL, "test"));
/* Check that we can append one array onto the end of the other,
* and that the array is extended and each new element copied
* into the new array.
*/
TEST_FEATURE ("with length given");
TEST_ALLOC_FAIL {
len = 0;
TEST_ALLOC_SAFE {
array = nih_str_array_new (NULL);
NIH_MUST (nih_str_array_add (&array, NULL, &len,
"foo"));
NIH_MUST (nih_str_array_add (&array, NULL, &len,
"bar"));
}
ret = nih_str_array_append (&array, NULL, &len, args);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ (len, 2);
TEST_EQ_STR (array[0], "foo");
TEST_EQ_STR (array[1], "bar");
TEST_EQ_P (array[2], NULL);
nih_free (array);
continue;
}
TEST_NE_P (ret, NULL);
TEST_EQ (len, 6);
TEST_EQ_STR (array[0], "foo");
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_STR (array[1], "bar");
TEST_ALLOC_PARENT (array[1], array);
TEST_EQ_STR (array[2], "this");
TEST_ALLOC_PARENT (array[2], array);
TEST_EQ_STR (array[3], "is");
TEST_ALLOC_PARENT (array[3], array);
TEST_EQ_STR (array[4], "a");
TEST_ALLOC_PARENT (array[4], array);
TEST_EQ_STR (array[5], "test");
TEST_ALLOC_PARENT (array[5], array);
TEST_EQ_P (array[6], NULL);
nih_free (array);
}
/* Check that we can omit the length, and have it calculated. */
TEST_FEATURE ("with no length given");
TEST_ALLOC_FAIL {
TEST_ALLOC_SAFE {
array = nih_str_array_new (NULL);
NIH_MUST (nih_str_array_add (&array, NULL, NULL,
"foo"));
NIH_MUST (nih_str_array_add (&array, NULL, NULL,
"bar"));
}
ret = nih_str_array_append (&array, NULL, NULL, args);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_STR (array[0], "foo");
TEST_EQ_STR (array[1], "bar");
TEST_EQ_P (array[2], NULL);
nih_free (array);
continue;
}
TEST_NE_P (ret, NULL);
TEST_EQ_STR (array[0], "foo");
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_STR (array[1], "bar");
TEST_ALLOC_PARENT (array[1], array);
TEST_EQ_STR (array[2], "this");
TEST_ALLOC_PARENT (array[2], array);
TEST_EQ_STR (array[3], "is");
TEST_ALLOC_PARENT (array[3], array);
TEST_EQ_STR (array[4], "a");
TEST_ALLOC_PARENT (array[4], array);
TEST_EQ_STR (array[5], "test");
TEST_ALLOC_PARENT (array[5], array);
TEST_EQ_P (array[6], NULL);
nih_free (array);
}
/* Check that we can pass a NULL array to get a copy of it, with
* the returned length containing the new length.
*/
TEST_FEATURE ("with NULL array and length");
TEST_ALLOC_FAIL {
len = 0;
array = NULL;
ret = nih_str_array_append (&array, NULL, &len, args);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ (len, 0);
TEST_EQ_P (array, NULL);
continue;
}
TEST_NE_P (ret, NULL);
TEST_EQ (len, 4);
TEST_EQ_STR (array[0], "this");
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_STR (array[1], "is");
TEST_ALLOC_PARENT (array[1], array);
TEST_EQ_STR (array[2], "a");
TEST_ALLOC_PARENT (array[2], array);
TEST_EQ_STR (array[3], "test");
TEST_ALLOC_PARENT (array[3], array);
TEST_EQ_P (array[4], NULL);
nih_free (array);
}
/* Check that we can pass a NULL array to get a copy of it, without
* passing the length in.
*/
TEST_FEATURE ("with NULL array and no length");
TEST_ALLOC_FAIL {
array = NULL;
ret = nih_str_array_append (&array, NULL, NULL, args);
if (test_alloc_failed) {
TEST_EQ_P (ret, NULL);
TEST_EQ_P (array, NULL);
continue;
}
TEST_NE_P (ret, NULL);
TEST_EQ_STR (array[0], "this");
TEST_ALLOC_PARENT (array[0], array);
TEST_EQ_STR (array[1], "is");
TEST_ALLOC_PARENT (array[1], array);
TEST_EQ_STR (array[2], "a");
TEST_ALLOC_PARENT (array[2], array);
TEST_EQ_STR (array[3], "test");
TEST_ALLOC_PARENT (array[3], array);
TEST_EQ_P (array[4], NULL);
nih_free (array);
}
nih_free (args);
}
void
test_str_wrap (void)
{
char *str;
TEST_FUNCTION ("nih_str_wrap");
/* Check that a string smaller than the wrap length is returned
* unaltered.
*/
TEST_FEATURE ("with no wrapping");
TEST_ALLOC_FAIL {
str = nih_str_wrap (NULL, "this is a test", 80, 0, 0);
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, "this is a test");
nih_free (str);
}
/* Check that a string with embedded new lines is returned with
* the line breaks preserved.
*/
TEST_FEATURE ("with embedded newlines");
TEST_ALLOC_FAIL {
str = nih_str_wrap (NULL, "this is\na test", 80, 0, 0);
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, "this is\na test");
nih_free (str);
}
/* Check that a smaller string is indented if one is given. */
TEST_FEATURE ("with no wrapping and indent");
TEST_ALLOC_FAIL {
str = nih_str_wrap (NULL, "this is a test", 80, 2, 0);
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, " this is a test");
nih_free (str);
}
/* Check that a string with embedded newlines gets an indent on
* each new line.
*/
TEST_FEATURE ("with embedded newlines and indent");
TEST_ALLOC_FAIL {
str = nih_str_wrap (NULL, "this is\na test", 80, 4, 2);
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, " this is\n a test");
nih_free (str);
}
/* Check that a long string is split at the wrap point. */
TEST_FEATURE ("with simple wrapping");
TEST_ALLOC_FAIL {
str = nih_str_wrap (NULL, "this is an example of a string "
"that will need wrapping to fit the line "
"length we set", 20, 0, 0);
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, ("this is an example\n"
"of a string that\n"
"will need wrapping\n"
"to fit the line\n"
"length we set"));
nih_free (str);
}
/* Check that a long string is split at the wrap point, and each
* new line indented, with the first line given a different indent.
*/
TEST_FEATURE ("with wrapping and indents");
TEST_ALLOC_FAIL {
str = nih_str_wrap (NULL, "this is an example of a string "
"that will need wrapping to fit the line "
"length we set", 20, 4, 2);
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, (" this is an\n"
" example of a\n"
" string that will\n"
" need wrapping to\n"
" fit the line\n"
" length we set"));
nih_free (str);
}
/* Check that a long string that would be split inside a long word
* is wrapepd before the word, and then split inside that word if it
* is still too long.
*/
TEST_FEATURE ("with split inside word");
TEST_ALLOC_FAIL {
str = nih_str_wrap (NULL, ("this string is supercalifragilis"
"ticexpialidocious even though the "
"sound of it is something quite "
"atrocious"), 30, 0, 0);
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, ("this string is\n"
"supercalifragilisticexpialidoc\n"
"ious even though the sound of\n"
"it is something quite\n"
"atrocious"));
nih_free (str);
}
/* Check that an indent is still applied if the split occurs inside
* a word.
*/
TEST_FEATURE ("with split inside word and indents");
TEST_ALLOC_FAIL {
str = nih_str_wrap (NULL, ("this string is supercalifragilis"
"ticexpialidocious even though the "
"sound of it is something quite "
"atrocious"), 30, 4, 2);
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, (" this string is\n"
" supercalifragilisticexpialid\n"
" ocious even though the sound\n"
" of it is something quite\n"
" atrocious"));
nih_free (str);
}
}
void
test_str_screen_width (void)
{
struct winsize winsize;
int pty, pts;
size_t len = 0;
TEST_FUNCTION ("nih_str_screen_width");
unsetenv ("COLUMNS");
winsize.ws_row = 24;
winsize.ws_col = 40;
winsize.ws_xpixel = 0;
winsize.ws_ypixel = 0;
openpty (&pty, &pts, NULL, NULL, &winsize);
/* Check that we can obtain the width of a screen, where one
* is available. It should match the number of columns in the
* pty we run this within.
*/
TEST_FEATURE ("with screen width");
TEST_DIVERT_STDOUT_FD (pts) {
len = nih_str_screen_width ();
}
TEST_EQ (len, 40);
/* Check that the COLUMNS environment variable overrides the width
* of the screen that we detect.
*/
TEST_FEATURE ("with COLUMNS variable");
putenv ("COLUMNS=30");
TEST_DIVERT_STDOUT_FD (pts) {
len = nih_str_screen_width ();
}
TEST_EQ (len, 30);
/* Check that we ignore a COLUMNS variable that's not an integer */
TEST_FEATURE ("with illegal COLUMNS variable");
putenv ("COLUMNS=30pt");
TEST_DIVERT_STDOUT_FD (pts) {
len = nih_str_screen_width ();
}
TEST_EQ (len, 40);
unsetenv ("COLUMNS");
close (pts);
close (pty);
/* Check that we fallback to assuming 80 columns if we don't have
* any luck with either the tty or COLUMNS variable.
*/
TEST_FEATURE ("with fallback to 80 columns");
pts = open ("/dev/null", O_RDWR | O_NOCTTY);
TEST_DIVERT_STDOUT_FD (pts) {
len = nih_str_screen_width ();
}
TEST_EQ (len, 80);
close (pts);
}
void
test_str_screen_wrap (void)
{
char *str = NULL;
struct winsize winsize;
int pty, pts;
TEST_FUNCTION ("nih_str_screen_wrap");
unsetenv ("COLUMNS");
winsize.ws_row = 24;
winsize.ws_col = 40;
winsize.ws_xpixel = 0;
winsize.ws_ypixel = 0;
openpty (&pty, &pts, NULL, NULL, &winsize);
/* Check that we correctly wrap text to the width of the screen
* when it is available.
*/
TEST_FEATURE ("with screen width");
TEST_ALLOC_FAIL {
TEST_DIVERT_STDOUT_FD (pts) {
str = nih_str_screen_wrap (
NULL, ("this is a string that "
"should need wrapping at "
"any different screen width "
"that we choose to set"),
0, 0);
}
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, ("this is a string that should need\n"
"wrapping at any different screen width\n"
"that we choose to set"));
nih_free (str);
}
/* Check that we wrap at the number specified in the COLUMNS
* variable in preference to the width of the screen.
*/
TEST_FEATURE ("with COLUMNS variable");
putenv ("COLUMNS=30");
TEST_ALLOC_FAIL {
TEST_DIVERT_STDOUT_FD (pts) {
str = nih_str_screen_wrap (
NULL, ("this is a string that "
"should need wrapping at "
"any different screen width "
"that we choose to set"),
0, 0);
}
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, ("this is a string that should\n"
"need wrapping at any\n"
"different screen width that\n"
"we choose to set"));
nih_free (str);
}
unsetenv ("COLUMNS");
close (pts);
close (pty);
/* Check that we fallback to assuming 80 columns if we don't have
* any luck with either the tty or COLUMNS variable.
*/
TEST_FEATURE ("with fallback to 80 columns");
pts = open ("/dev/null", O_RDWR | O_NOCTTY);
TEST_ALLOC_FAIL {
TEST_DIVERT_STDOUT_FD (pts) {
str = nih_str_screen_wrap (
NULL, ("this is a string that "
"should need wrapping at "
"any different screen width "
"that we choose to set"),
0, 0);
}
if (test_alloc_failed) {
TEST_EQ_P (str, NULL);
continue;
}
TEST_EQ_STR (str, ("this is a string that should need "
"wrapping at any different screen width "
"that\n"
"we choose to set"));
nih_free (str);
}
close (pts);
}
int
main (int argc,
char *argv[])
{
test_sprintf ();
test_vsprintf ();
test_strdup ();
test_strndup ();
test_strcat ();
test_strncat ();
test_strcat_sprintf ();
test_strcat_vsprintf ();
test_str_split ();
test_array_new ();
test_array_add ();
test_array_addn ();
test_array_addp ();
test_array_copy ();
test_array_append ();
test_str_wrap ();
test_str_screen_width ();
test_str_screen_wrap ();
return 0;
}