Index: src/libbu/tests/bu_str.c
===================================================================
--- src/libbu/tests/bu_str.c	(revision 0)
+++ src/libbu/tests/bu_str.c	(working copy)
@@ -0,0 +1,191 @@
+/*                       B U _ S T R . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2014 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This 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 this file; see the file named COPYING for more
+ * information.
+ */
+
+#include "common.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bu.h"
+
+#include "vmath.h"
+
+#define SIGNUM(x) ((x > 0) - (x < 0))
+
+static int
+test_bu_strlcatm(int argc, char *argv[])
+{
+    char *dst;
+    int ret, expected_ret;
+    int size;
+    int len;
+
+    if (argc != 7) {
+	bu_exit(1, "ERROR: input format is string1 string2 result_size expected_ret expected_result [%s]\n", argv[0]);
+    }
+
+    sscanf(argv[4], "%d", &size);
+    sscanf(argv[5], "%d", &expected_ret);
+    if (size > 0) {
+	dst = (char *)bu_malloc(size, "test_bu_strlcatm");
+    } else {
+	dst = (char *)bu_malloc(1, "test_bu_strlcatm");
+	dst[0] = '\0';
+    }
+    bu_strlcpym(dst, argv[2], size, "test_bu_strlcatm");
+
+    ret = bu_strlcatm(dst, argv[3], size, "test_bu_strlcatm");
+    len = strlen(dst);
+
+    printf("Result: \"%s\" (return value %d)", dst, ret);
+
+    return !(BU_STR_EQUAL(argv[6], dst)
+	     && (expected_ret == ret)
+	     && len <= size
+	     && dst[len] == '\0');
+}
+
+static int
+test_bu_strlcpym(int argc, char *argv[])
+{
+    char *dst;
+    int ret, expected_ret;
+    int size;
+    int len;
+
+    if (argc != 6) {
+	bu_exit(1, "ERROR: input format is string result_size expected_ret expected_result [%s]\n", argv[0]);
+    }
+
+    sscanf(argv[3], "%d", &size);
+    sscanf(argv[4], "%d", &expected_ret);
+    if (size > 0) {
+	dst = (char *)bu_malloc(size, "test_bu_strlcpym");
+    } else {
+	dst = (char *)bu_malloc(1, "test_bu_strlcpym");
+	dst[0] = '\0';
+    }
+
+    ret = bu_strlcpym(dst, argv[2], size, "test_bu_strlcpym");
+    len = strlen(dst);
+
+    printf("Result: \"%s\" (return value %d)", dst, ret);
+
+    return !(BU_STR_EQUAL(argv[5], dst)
+	     && (expected_ret == ret)
+	     && len <= size
+	     && dst[len] == '\0');
+}
+
+static int
+test_bu_strdupm(int argc, char *argv[])
+{
+    char *dst;
+
+    if (argc != 3) {
+	bu_exit(1, "ERROR: input format is string [%s]\n", argv[0]);
+    }
+
+    dst = bu_strdupm(argv[2], "test_bu_strlcpym");
+
+    printf("Result: \"%s\"", dst);
+
+    return !(BU_STR_EQUAL(argv[2], dst));
+}
+
+static int
+test_bu_strcmp_like_functions(int argc, char *argv[], int (*fun)(const char *, const char *))
+{
+    int ret, expected_ret;
+
+    if (argc != 5) {
+	bu_exit(1, "ERROR: input format is string1 string2 expected_ret [%s]\n", argv[0]);
+    }
+    sscanf(argv[4], "%d", &expected_ret);
+
+    ret = (fun)(argv[2], argv[3]);
+
+    printf("Result: %d", ret);
+
+    return !(SIGNUM(expected_ret) == SIGNUM(ret));
+}
+
+static int
+test_bu_strncmp_like_functions(int argc, char *argv[], int (*fun)(const char *, const char *, size_t))
+{
+    int n;
+    int ret, expected_ret;
+
+    if (argc != 6) {
+	bu_exit(1, "ERROR: input format is string1 string2 n expected_ret [%s]\n", argv[0]);
+    }
+    sscanf(argv[4], "%d", &n);
+    sscanf(argv[5], "%d", &expected_ret);
+
+    ret = (*fun)(argv[2], argv[3], n);
+
+    printf("Result: %d", ret);
+
+    return !(SIGNUM(expected_ret) == SIGNUM(ret));
+}
+
+int
+main(int argc, char *argv[])
+{
+    int function_num = 0;
+
+    if (argc < 2) {
+	bu_exit(1, "ERROR: input format is function_num function_test_args [%s]\n", argv[0]);
+    }
+
+    sscanf(argv[1], "%d", &function_num);
+
+    switch (function_num) {
+	case 1:
+	    return test_bu_strlcatm(argc, argv);
+	case 2:
+	    return test_bu_strlcpym(argc, argv);
+	case 3:
+	    return test_bu_strdupm(argc, argv);
+	case 4:
+	    return test_bu_strcmp_like_functions(argc, argv, &bu_strcmp);
+	case 5:
+	    return test_bu_strncmp_like_functions(argc, argv, &bu_strncmp);
+	case 6:
+	    return test_bu_strcmp_like_functions(argc, argv, &bu_strcasecmp);
+	case 7:
+	    return test_bu_strncmp_like_functions(argc, argv, &bu_strncasecmp);
+    }
+
+    bu_log("ERROR: function_num %d is not valid [%s]\n", function_num, argv[0]);
+    return 1;
+}
+
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */
Index: src/libbu/tests/CMakeLists.txt
===================================================================
--- src/libbu/tests/CMakeLists.txt	(revision 63578)
+++ src/libbu/tests/CMakeLists.txt	(working copy)
@@ -284,8 +284,117 @@
 # integers or floats.
 
 add_test(bu_color_to_rgb_floats_1 tester_bu_color 4 192,78,214)
+#
+# ************ str.c tests ************
+#
 
+# For tester_bu_str, the input format is as follows:
 #
+# tester_bu_str <function number> <args>
+BRLCAD_ADDEXEC(tester_bu_str bu_str.c libbu NO_INSTALL)
+
+# For function #1 (bu_strlcatm) the <args> format is as follows:
+#
+# string1 string2 result_size expected_ret expected_result
+#
+# Where string1 and string2 are the strings to concatenate,
+# result_size is the size for the buffer that the result will be
+# stored in, expected_ret is the expected return value of the
+# function, and expected_result is the expected resultant string in
+# dst.
+
+add_test(bu_strlcatm_valid_1 tester_bu_str 1 "abc" "def" 7 6 "abcdef")
+add_test(bu_strlcatm_valid_2 tester_bu_str 1 "abc" "def" 8 6 "abcdef")
+add_test(bu_strlcatm_bad_size_1 tester_bu_str 1 "abc" "def" 0 0 "")
+add_test(bu_strlcatm_bad_size_2 tester_bu_str 1 "abc" "def" 5 4 "abcd")
+
+# For function #2 (bu_strlcpym) the <args> format is as follows:
+#
+# string result_size expected_ret expected_result
+#
+# Where string is the string to copy, result_size is the size of the
+# result buffer, expected_ret is the expected return value of the
+# function, and expected_result is the expected contents of the copied
+# string.
+
+add_test(bu_strlcpym_valid_1 tester_bu_str 2 "abcdef" 7 6 "abcdef")
+add_test(bu_strlcpym_valid_2 tester_bu_str 2 "abcdef" 8 6 "abcdef")
+add_test(bu_strlcpym_bad_size_1 tester_bu_str 2 "abcdef" 0 0 "")
+add_test(bu_strlcpym_bad_size_2 tester_bu_str 2 "abcdef" 5 4 "abcd")
+
+# For function #3 (bu_strdupm) the <args> format is as follows:
+#
+# string
+#
+# Where string is the string to duplicate.
+
+add_test(bu_strdupm_1 tester_bu_str 3 "abcdef")
+
+# For function #4 (bu_strcmp) the <args> format is as follows:
+#
+# string1 string2 expected_ret
+#
+# Where string1 and string2 are the strings to compare, and
+# expected_ret is a number of the same sign as the expected comparison
+# result.
+
+add_test(bu_strcmp_equal_1 tester_bu_str 4 "abcd" "abcd" 0)
+add_test(bu_strcmp_less_1 tester_bu_str 4 "a" "b" -1)
+add_test(bu_strcmp_less_2 tester_bu_str 4 "abCD" "abcd" -1)
+add_test(bu_strcmp_greater_1 tester_bu_str 4 "b" "a" 1)
+add_test(bu_strcmp_greater_2 tester_bu_str 4 "abcd" "abCD" 1)
+
+# For function #5 (bu_strncmp) the <args> format is as follows:
+#
+# string1 string2 n expected_ret
+#
+# Where string1 and string2 are the strings to compare, n is the
+# length to give strncmp, and expected_ret is a number of the same
+# sign as the expected comparison result.
+
+add_test(bu_strncmp_equal_1 tester_bu_str 5 "abcd" "abcd" 4 0)
+add_test(bu_strncmp_equal_2 tester_bu_str 5 "abcd" "abcd" 3 0)
+add_test(bu_strncmp_equal_3 tester_bu_str 5 "abcd" "abcd" 5 0)
+add_test(bu_strncmp_equal_4 tester_bu_str 5 "abcd" "abc" 3 0)
+add_test(bu_strncmp_equal_5 tester_bu_str 5 "abcd" "abce" 3 0)
+add_test(bu_strncmp_less_1 tester_bu_str 5 "abcd" "abce" 4 -1)
+add_test(bu_strncmp_less_2 tester_bu_str 5 "abCD" "abcd" 4 -1)
+add_test(bu_strncmp_greater_1 tester_bu_str 5 "abcd" "abc" 4 1)
+add_test(bu_strncmp_greater_2 tester_bu_str 5 "abcd" "abCD" 4 1)
+
+# For function #6 (bu_strcasecmp) the <args> format is as follows:
+#
+# string1 string2 expected_ret
+#
+# Where string1 and string2 are the strings to compare, and
+# expected_ret is a number of the same sign as the expected comparison
+# result.
+
+add_test(bu_strcasecmp_equal_1 tester_bu_str 6 "abcd" "abcd" 0)
+add_test(bu_strcasecmp_equal_2 tester_bu_str 6 "abCD" "abcd" 0)
+add_test(bu_strcasecmp_equal_3 tester_bu_str 6 "abcd" "abCD" 0)
+add_test(bu_strcasecmp_less_1 tester_bu_str 4 "a" "b" -1)
+add_test(bu_strcasecmp_greater_1 tester_bu_str 4 "b" "a" 1)
+
+# For function #7 (bu_strncasecmp) the <args> format is as follows:
+#
+# string1 string2 n expected_ret
+#
+# Where string1 and string2 are the strings to compare, n is the
+# length to give strncmp, and expected_ret is a number of the same
+# sign as the expected comparison result.
+
+add_test(bu_strncasecmp_equal_1 tester_bu_str 7 "abcd" "abcd" 4 0)
+add_test(bu_strncasecmp_equal_2 tester_bu_str 7 "abcd" "abcd" 3 0)
+add_test(bu_strncasecmp_equal_3 tester_bu_str 7 "abcd" "abcd" 5 0)
+add_test(bu_strncasecmp_equal_4 tester_bu_str 7 "abcd" "abc" 3 0)
+add_test(bu_strncasecmp_equal_5 tester_bu_str 7 "abcd" "abce" 3 0)
+add_test(bu_strncasecmp_equal_6 tester_bu_str 7 "abCD" "abcd" 4 0)
+add_test(bu_strncasecmp_equal_7 tester_bu_str 7 "abcd" "abCD" 4 0)
+add_test(bu_strncasecmp_less_1 tester_bu_str 7 "abcd" "abce" 4 -1)
+add_test(bu_strncasecmp_greater_1 tester_bu_str 7 "abcd" "abc" 4 1)
+
+#
 #  *********** badmagic.c tests ************
 #
 
