aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--include/str.h7
-rw-r--r--lib/str.c149
-rw-r--r--tests/CMakeLists.txt18
-rw-r--r--tests/framework.h61
-rw-r--r--tests/test_str_endswith.c22
-rw-r--r--tests/test_str_isempty.c22
-rw-r--r--tests/test_str_isquoted.c21
-rw-r--r--tests/test_str_isrelational.c27
-rw-r--r--tests/test_str_join.c25
-rw-r--r--tests/test_str_join_ex.c24
-rw-r--r--tests/test_str_lstrip.c36
-rw-r--r--tests/test_str_num_chars_generic.c31
-rw-r--r--tests/test_str_print_banner.c43
-rw-r--r--tests/test_str_split.c29
-rw-r--r--tests/test_str_startswith.c22
-rw-r--r--tests/test_str_strchrdel.c61
-rw-r--r--tests/test_str_strchroff.c31
-rw-r--r--tests/test_str_strdeldup.c31
-rw-r--r--tests/test_str_strdelsuffix.c24
-rw-r--r--tests/test_str_strip.c36
-rw-r--r--tests/test_str_strsort.c36
-rw-r--r--tests/test_str_strstr_array.c28
-rw-r--r--tests/test_str_substring_between.c28
24 files changed, 777 insertions, 40 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ba01f3b..189100d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,9 +1,13 @@
cmake_minimum_required(VERSION 3.11)
project(spm C)
+
+include(CTest)
include(CheckSymbolExists)
+
set(CMAKE_C_STANDARD 99)
set(CMAKE_INSTALL_RPATH $ORIGIN/../lib)
+enable_testing()
check_symbol_exists(strsep string.h HAVE_STRSEP)
check_symbol_exists(reallocarray stdlib.h HAVE_REALLOCARRAY)
configure_file(${CMAKE_SOURCE_DIR}/config.h.in ${CMAKE_BINARY_DIR}/include/config.h)
@@ -12,3 +16,4 @@ add_subdirectory(lib)
add_subdirectory(src)
add_subdirectory(include)
add_subdirectory(scripts)
+add_subdirectory(tests)
diff --git a/include/str.h b/include/str.h
index e313b84..5e6d30d 100644
--- a/include/str.h
+++ b/include/str.h
@@ -4,6 +4,11 @@
#ifndef SPM_STR_H
#define SPM_STR_H
+#define SPM_SORT_ALPHA 1 << 0
+#define SPM_SORT_NUMERIC 1 << 1
+#define SPM_SORT_LEN_ASCENDING 1 << 2
+#define SPM_SORT_LEN_DESCENDING 1 << 3
+
int num_chars(const char *sptr, int ch);
int startswith(const char *sptr, const char *pattern);
int endswith(const char *sptr, const char *pattern);
@@ -16,7 +21,7 @@ void split_free(char **ptr);
char *join(char **arr, const char *separator);
char *join_ex(char *separator, ...);
char *substring_between(char *sptr, const char *delims);
-void strsort(char **arr);
+void strsort(char **arr, unsigned int sort_mode);
int find_in_file(const char *filename, const char *pattern);
int isrelational(char ch);
void print_banner(const char *s, int len);
diff --git a/lib/str.c b/lib/str.c
index 5db3adc..f8d2e22 100644
--- a/lib/str.c
+++ b/lib/str.c
@@ -27,7 +27,7 @@ int num_chars(const char *sptr, int ch) {
* @return 1 = found, 0 = not found, -1 = error
*/
int startswith(const char *sptr, const char *pattern) {
- if (!sptr) {
+ if (!sptr || !pattern) {
return -1;
}
for (size_t i = 0; i < strlen(pattern); i++) {
@@ -46,7 +46,7 @@ int startswith(const char *sptr, const char *pattern) {
* @return 1 = found, 0 = not found, -1 = error
*/
int endswith(const char *sptr, const char *pattern) {
- if (!sptr) {
+ if (!sptr || !pattern) {
return -1;
}
ssize_t sptr_size = strlen(sptr);
@@ -81,6 +81,10 @@ int endswith(const char *sptr, const char *pattern) {
* @param chars a string containing characters (e.g. " \n" would delete whitespace and line feeds)
*/
void strchrdel(char *sptr, const char *chars) {
+ if (sptr == NULL || chars == NULL) {
+ return;
+ }
+
while (*sptr != '\0') {
for (int i = 0; chars[i] != '\0'; i++) {
if (*sptr == chars[i]) {
@@ -111,12 +115,23 @@ long int strchroff(const char *sptr, int ch) {
char *orig = strdup(sptr);
char *tmp = orig;
long int result = 0;
+
+ int found = 0;
+ size_t i = 0;
+
while (*tmp != '\0') {
if (*tmp == ch) {
+ found = 1;
break;
}
tmp++;
+ i++;
}
+
+ if (found == 0 && i == strlen(sptr)) {
+ return -1;
+ }
+
result = tmp - orig;
free(orig);
@@ -164,13 +179,14 @@ void strdelsuffix(char *sptr, const char *suffix) {
*/
char** split(char *_sptr, const char* delim)
{
- if (_sptr == NULL) {
+ if (_sptr == NULL || delim == NULL) {
return NULL;
}
size_t split_alloc = 0;
// Duplicate the input string and save a copy of the pointer to be freed later
char *orig = strdup(_sptr);
char *sptr = orig;
+
if (!sptr) {
return NULL;
}
@@ -179,6 +195,12 @@ char** split(char *_sptr, const char* delim)
for (size_t i = 0; i < strlen(delim); i++) {
split_alloc += num_chars(sptr, delim[i]);
}
+
+ if (split_alloc == 0) {
+ free(orig);
+ return NULL;
+ }
+
// Preallocate enough records based on the number of delimiters
char **result = (char **)calloc(split_alloc + 2, sizeof(char *));
if (!result) {
@@ -243,7 +265,7 @@ char *join(char **arr, const char *separator) {
int records = 0;
size_t total_bytes = 0;
- if (!arr) {
+ if (!arr || !separator) {
return NULL;
}
@@ -278,6 +300,10 @@ char *join_ex(char *separator, ...) {
char *current = NULL; // Current argument
char *result = NULL; // Output string
+ if (separator == NULL) {
+ return NULL;
+ }
+
// Initialize array
argv = calloc(argc + 1, sizeof(char *));
if (argv == NULL) {
@@ -339,6 +365,10 @@ char *join_ex(char *separator, ...) {
* @return success=text between delimiters, failure=NULL
*/
char *substring_between(char *sptr, const char *delims) {
+ if (sptr == NULL || delims == NULL) {
+ return NULL;
+ }
+
// Ensure we have enough delimiters to continue
size_t delim_count = strlen(delims);
if (delim_count != 2) {
@@ -346,18 +376,23 @@ char *substring_between(char *sptr, const char *delims) {
}
// Create pointers to the delimiters
- char *start = strpbrk(sptr, &delims[0]);
- char *end = strpbrk(sptr, &delims[1]);
+ char *start = strchr(sptr, delims[0]);
+ if (start == NULL || strlen(start) == 0) {
+ return NULL;
+ }
- // Ensure the string has both delimiters
- if (!start || !end) {
+ char *end = strchr(start + 1, delims[1]);
+ if (end == NULL) {
return NULL;
}
start++; // ignore leading delimiter
// Get length of the substring
- size_t length = end - start;
+ ssize_t length = strlen(start);
+ if (length < 0) {
+ return NULL;
+ }
char *result = (char *)calloc(length + 1, sizeof(char));
if (!result) {
@@ -376,33 +411,34 @@ char *substring_between(char *sptr, const char *delims) {
}
/*
- * Helper function for `strsort`
+ * Comparison functions for `strsort`
*/
-static int _strsort_compare(const void *a, const void *b) {
- const char *aa = *(const char**)a;
- const char *bb = *(const char**)b;
+static int _strsort_alpha_compare(const void *a, const void *b) {
+ const char *aa = *(const char **)a;
+ const char *bb = *(const char **)b;
int result = strcmp(aa, bb);
return result;
}
-/**
- * Sort an array of strings alphabetically
- * @param arr
- */
-void strsort(char **arr) {
- size_t arr_size = 0;
+static int _strsort_numeric_compare(const void *a, const void *b) {
+ const char *aa = *(const char **)a;
+ const char *bb = *(const char **)b;
- // Determine size of array
- for (size_t i = 0; arr[i] != NULL; i++) {
- arr_size = i;
+ if (isdigit(*aa) && isdigit(*bb)) {
+ int ia = atoi(aa);
+ int ib = atoi(bb);
+
+ if (ia == ib) {
+ return 0;
+ } else if (ia < ib) {
+ return -1;
+ } else if (ia < ib) {
+ return 1;
+ }
}
- qsort(arr, arr_size, sizeof(char *), _strsort_compare);
}
-/*
- * Helper function for `strsortlen`
- */
-static int _strsortlen_asc_compare(const void *a, const void *b) {
+static int _strsort_asc_compare(const void *a, const void *b) {
const char *aa = *(const char**)a;
const char *bb = *(const char**)b;
size_t len_a = strlen(aa);
@@ -413,31 +449,45 @@ static int _strsortlen_asc_compare(const void *a, const void *b) {
/*
* Helper function for `strsortlen`
*/
-static int _strsortlen_dsc_compare(const void *a, const void *b) {
+static int _strsort_dsc_compare(const void *a, const void *b) {
const char *aa = *(const char**)a;
const char *bb = *(const char**)b;
size_t len_a = strlen(aa);
size_t len_b = strlen(bb);
return len_a < len_b;
}
+
/**
- * Sort an array of strings by length
+ * Sort an array of strings
* @param arr
*/
-void strsortlen(char **arr, unsigned int sort_mode) {
+void strsort(char **arr, unsigned int sort_mode) {
+ if (arr == NULL) {
+ return;
+ }
+
typedef int (*compar)(const void *, const void *);
+ // Default mode is alphabetic sort
+ compar fn = _strsort_alpha_compare;
- compar fn = _strsortlen_asc_compare;
- if (sort_mode != 0) {
- fn = _strsortlen_dsc_compare;
+ if (sort_mode == SPM_SORT_LEN_DESCENDING) {
+ fn = _strsort_dsc_compare;
+ } else if (sort_mode == SPM_SORT_LEN_ASCENDING) {
+ fn = _strsort_asc_compare;
+ } else if (sort_mode == SPM_SORT_ALPHA) {
+ fn = _strsort_alpha_compare; // ^ still selectable though ^
+ } else if (sort_mode == SPM_SORT_NUMERIC) {
+ fn = _strsort_numeric_compare;
}
size_t arr_size = 0;
- // Determine size of array
+ // Determine size of array (+ terminator)
for (size_t i = 0; arr[i] != NULL; i++) {
arr_size = i;
}
+ arr_size++;
+
qsort(arr, arr_size, sizeof(char *), fn);
}
@@ -448,7 +498,7 @@ void strsortlen(char **arr, unsigned int sort_mode) {
* @return yes=`pointer to string`, no=`NULL`, failure=`NULL`
*/
char *strstr_array(char **arr, const char *str) {
- if (arr == NULL) {
+ if (arr == NULL || str == NULL) {
return NULL;
}
@@ -485,19 +535,22 @@ char **strdeldup(char **arr) {
size_t i = 0;
while(i < records) {
// Search for value in results
- if (strstr_array(result, arr[i]) == 0) {
+ if (strstr_array(result, arr[i]) != NULL) {
// value already exists in results so ignore it
i++;
continue;
}
// Store unique value
- result[rec] = (char *)calloc(strlen(arr[i]) + 1, sizeof(char));
+ result[rec] = strdup(arr[i]);
if (!result[rec]) {
+ for (size_t die = 0; result[die] != NULL; die++) {
+ free(result[die]);
+ }
free(result);
return NULL;
}
- memcpy(result[rec], arr[i], strlen(arr[i]) + 1);
+
i++;
rec++;
}
@@ -511,6 +564,11 @@ char **strdeldup(char **arr) {
char *lstrip(char *sptr) {
char *tmp = sptr;
size_t bytes = 0;
+
+ if (sptr == NULL) {
+ return NULL;
+ }
+
while (isblank(*tmp) || isspace(*tmp)) {
bytes++;
tmp++;
@@ -528,6 +586,10 @@ char *lstrip(char *sptr) {
* @return truncated string
*/
char *strip(char *sptr) {
+ if (sptr == NULL) {
+ return NULL;
+ }
+
size_t len = strlen(sptr);
if (len == 0) {
return sptr;
@@ -556,9 +618,13 @@ char *strip(char *sptr) {
* @return 0=not empty, 1=empty
*/
int isempty(char *sptr) {
+ if (sptr == NULL) {
+ return -1;
+ }
+
char *tmp = sptr;
while (*tmp) {
- if (!isblank(*tmp) || !isspace(*tmp)) {
+ if (!isblank(*tmp) && !isspace(*tmp) && !iscntrl(*tmp)) {
return 0;
}
tmp++;
@@ -573,6 +639,11 @@ int isempty(char *sptr) {
*/
int isquoted(char *sptr) {
const char *quotes = "'\"";
+
+ if (sptr == NULL) {
+ return -1;
+ }
+
char *quote_open = strpbrk(sptr, quotes);
if (!quote_open) {
return 0;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..0eb8e34
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,18 @@
+include_directories(
+ ${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_BINARY_DIR}/include
+)
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/tests)
+set(CTEST_BINARY_DIRECTORY ${PROJECT_BINARY_DIR}/tests)
+
+file(GLOB files "test_*.c")
+
+foreach(file ${files})
+ string(REGEX REPLACE "(^.*/|\\.[^.]*$)" "" file_without_ext ${file})
+ add_executable(${file_without_ext} ${file})
+ target_link_libraries(${file_without_ext} libspm ${PROJECT_LIBS})
+ add_test(${file_without_ext} ${file_without_ext})
+ set_tests_properties(${file_without_ext}
+ PROPERTIES
+ TIMEOUT 120)
+endforeach()
diff --git a/tests/framework.h b/tests/framework.h
new file mode 100644
index 0000000..1e5adaa
--- /dev/null
+++ b/tests/framework.h
@@ -0,0 +1,61 @@
+#ifndef SPM_FRAMEWORK_H
+#define SPM_FRAMEWORK_H
+#include <limits.h>
+#include <fcntl.h>
+
+union TestValue {
+ const char *sptr;
+ char **slptr;
+ char character;
+ unsigned int unsigned_integer;
+ signed int signed_integer;
+ float floating;
+ char str[PATH_MAX];
+};
+
+struct TestCase {
+ union TestValue caseValue;
+ union TestValue inputValue;
+ union TestValue truthValue;
+};
+
+char *array_to_string(char **array, const char *sep) {
+ char *buffer = NULL;
+ size_t buffer_size = 0;
+ size_t records = 0;
+
+ if (array == NULL || sep == NULL) {
+ return NULL;
+ }
+
+ for (records = 0; array[records] != NULL; records++) {
+ buffer_size += strlen(array[records]) + 1;
+ }
+ buffer_size++;
+
+ buffer = calloc(buffer_size, sizeof(char));
+ if (buffer == NULL) {
+ perror("could not allocate buffer");
+ exit(1);
+ }
+
+ for (size_t i = 0; i < records; i++) {
+ for (size_t ch = 0; ch < strlen(array[i]); ch++) {
+ strncat(buffer, &array[i][ch], 1);
+ }
+ if ((records - (i + 1)) > 0)
+ strncat(buffer, sep, 2);
+ }
+ return buffer;
+}
+
+#define myassert(condition, ...) \
+ do { \
+ if (!(condition)) { \
+ fprintf(stderr, "%s:%d:%s :: ", __FILE__, __LINE__, __FUNCTION__); \
+ fprintf(stderr, __VA_ARGS__); \
+ return 1; \
+ } \
+ } while (0)
+
+#endif //SPM_FRAMEWORK_H
diff --git a/tests/test_str_endswith.c b/tests/test_str_endswith.c
new file mode 100644
index 0000000..bcbf249
--- /dev/null
+++ b/tests/test_str_endswith.c
@@ -0,0 +1,22 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "'%s' does not end with '%s' (%d)\n";
+struct TestCase testCase[] = {
+ {.inputValue.sptr = "gumball", .caseValue.sptr = "abracadabra brisket gumball", .truthValue.signed_integer = 1},
+ {.inputValue.sptr = "y", .caseValue.sptr = "balloons are falling from the sky", .truthValue.signed_integer = 1},
+ {.inputValue.sptr = "ickly", .caseValue.sptr = "mangled mangoes oxidize quickly", .truthValue.signed_integer = 1},
+ {.inputValue.sptr = "B", .caseValue.sptr = "bBbB", .truthValue.signed_integer = 1},
+ {.inputValue.sptr = NULL, .caseValue.sptr = "bBbB", .truthValue.signed_integer = -1},
+ {.inputValue.sptr = "test", .caseValue.sptr = NULL, .truthValue.signed_integer = -1},
+ {.inputValue.sptr = NULL, .caseValue.sptr = NULL, .truthValue.signed_integer = -1},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i > numCases; i++) {
+ int result = endswith(testCase[i].caseValue.sptr, testCase[i].inputValue.sptr);
+ myassert(result == testCase[i].truthValue.signed_integer, testFmt, testCase[i].inputValue.str, testCase[i].truthValue.sptr, result);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_isempty.c b/tests/test_str_isempty.c
new file mode 100644
index 0000000..840b811
--- /dev/null
+++ b/tests/test_str_isempty.c
@@ -0,0 +1,22 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case: '%s': returned %d, expected %d\n";
+struct TestCase testCase[] = {
+ {.caseValue.sptr = " not empty", .truthValue.signed_integer = 0},
+ {.caseValue.sptr = "not empty", .truthValue.signed_integer = 0},
+ {.caseValue.sptr = " ", .truthValue.signed_integer = 1},
+ {.caseValue.sptr = "\t", .truthValue.signed_integer = 1},
+ {.caseValue.sptr = "\n", .truthValue.signed_integer = 1},
+ {.caseValue.sptr = "", .truthValue.signed_integer = 1},
+ {.caseValue.sptr = NULL, .truthValue.signed_integer = -1},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ int result = isempty(testCase[i].caseValue.sptr);
+ myassert(result == testCase[i].truthValue.signed_integer, testFmt, testCase[i].caseValue.sptr, result, testCase[i].truthValue.sptr);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_isquoted.c b/tests/test_str_isquoted.c
new file mode 100644
index 0000000..2f8f133
--- /dev/null
+++ b/tests/test_str_isquoted.c
@@ -0,0 +1,21 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case: '%s': returned %d, expected %d\n";
+struct TestCase testCase[] = {
+ {.caseValue.sptr = "not quoted", .truthValue.signed_integer = 0},
+ {.caseValue.sptr = "\"double quoted\"", .truthValue.signed_integer = 1},
+ {.caseValue.sptr = "\'single quoted\'", .truthValue.signed_integer = 1},
+ {.caseValue.sptr = "\"no closing quote", .truthValue.signed_integer = 0},
+ {.caseValue.sptr = "no opening quote\"", .truthValue.signed_integer = 0},
+ {.caseValue.sptr = NULL, .truthValue.signed_integer = -1},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ int result = isquoted(testCase[i].caseValue.sptr);
+ myassert(result == testCase[i].truthValue.signed_integer, testFmt, testCase[i].caseValue.sptr, result, testCase[i].truthValue.signed_integer);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_isrelational.c b/tests/test_str_isrelational.c
new file mode 100644
index 0000000..92c4803
--- /dev/null
+++ b/tests/test_str_isrelational.c
@@ -0,0 +1,27 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case: '%c': returned %d, expected %d\n";
+struct TestCase testCase[] = {
+ {.caseValue.character = '~', .truthValue.signed_integer = 1},
+ {.caseValue.character = '!', .truthValue.signed_integer = 1},
+ {.caseValue.character = '=', .truthValue.signed_integer = 1},
+ {.caseValue.character = '<', .truthValue.signed_integer = 1},
+ {.caseValue.character = '>', .truthValue.signed_integer = 1},
+ {.caseValue.character = 'u', .truthValue.signed_integer = 0},
+ {.caseValue.character = 'd', .truthValue.signed_integer = 0},
+ {.caseValue.character = 'l', .truthValue.signed_integer = 0},
+ {.caseValue.character = 'r', .truthValue.signed_integer = 0},
+ {.caseValue.character = 'b', .truthValue.signed_integer = 0},
+ {.caseValue.character = 'a', .truthValue.signed_integer = 0},
+ {.caseValue.character = '\n', .truthValue.signed_integer = 0},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ int result = isrelational(testCase[i].caseValue.character);
+ myassert(result == testCase[i].truthValue.signed_integer, testFmt, testCase[i].caseValue.character, result, testCase[i].truthValue.signed_integer);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_join.c b/tests/test_str_join.c
new file mode 100644
index 0000000..4cd9a5c
--- /dev/null
+++ b/tests/test_str_join.c
@@ -0,0 +1,25 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case: (array){%s}: returned '%s', expected '%s'\n";
+struct TestCase testCase[] = {
+ {.inputValue.sptr = " ", .caseValue.slptr = (char *[]){"one", "two", "three", NULL}, .truthValue.sptr = "one two three"},
+ {.inputValue.sptr = "|", .caseValue.slptr = (char *[]){"one", "two", "three", NULL}, .truthValue.sptr = "one|two|three"},
+ {.inputValue.sptr = ",", .caseValue.slptr = (char *[]){"one", "two", "three", NULL}, .truthValue.sptr = "one,two,three"},
+ {.inputValue.sptr = "_", .caseValue.slptr = (char *[]){"one", NULL}, .truthValue.sptr = "one"},
+ {.inputValue.sptr = "b", .caseValue.sptr = NULL, .truthValue.slptr = NULL},
+ {.inputValue.sptr = NULL, .caseValue.sptr = NULL, .truthValue.slptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char *result = join(testCase[i].caseValue.slptr, testCase[i].inputValue.sptr);
+ if (testCase[i].truthValue.sptr == NULL && result == NULL) {
+ continue;
+ }
+ myassert(strcmp(result, testCase[i].truthValue.sptr) == 0, testFmt, array_to_string(testCase[i].caseValue.slptr, ", "), result, testCase[i].truthValue.sptr);
+ free(result);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_join_ex.c b/tests/test_str_join_ex.c
new file mode 100644
index 0000000..7ce787f
--- /dev/null
+++ b/tests/test_str_join_ex.c
@@ -0,0 +1,24 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case: returned '%s', expected '%s'\n";
+struct TestCase testCase[] = {
+ {.inputValue.sptr = " ", .truthValue.sptr = "one two three"},
+ {.inputValue.sptr = "|", .truthValue.sptr = "one|two|three"},
+ {.inputValue.sptr = ",", .truthValue.sptr = "one,two,three"},
+ {.inputValue.sptr = "b", .truthValue.sptr = "onebtwobthree"},
+ {.inputValue.sptr = NULL, .truthValue.slptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char *result = join_ex(testCase[i].inputValue.sptr, "one", "two", "three", NULL);
+ if (testCase[i].truthValue.sptr == NULL && result == NULL) {
+ continue;
+ }
+ myassert(strcmp(result, testCase[i].truthValue.sptr) == 0, testFmt, result, testCase[i].truthValue.sptr);
+ free(result);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_lstrip.c b/tests/test_str_lstrip.c
new file mode 100644
index 0000000..fa0c187
--- /dev/null
+++ b/tests/test_str_lstrip.c
@@ -0,0 +1,36 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case '%s': returned '%s', expected '%s'\n";
+struct TestCase testCase[] = {
+ {.caseValue.str = " four spaces", .truthValue.sptr = "four spaces"},
+ {.caseValue.str = "\tone tab", .truthValue.sptr = "one tab"},
+ {.caseValue.str = "\na new line", .truthValue.sptr = "a new line"},
+ {.caseValue.sptr = NULL, .truthValue.sptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char *caseValue = NULL;
+ char *orig = NULL;
+ char *result = NULL;
+
+ if (testCase[i].caseValue.sptr != NULL) {
+ caseValue = strdup(testCase[i].caseValue.str);
+ orig = strdup(caseValue);
+ result = lstrip(caseValue);
+ }
+
+ if (testCase[i].truthValue.sptr == NULL && result == NULL) {
+ continue;
+ } else if (testCase[i].truthValue.sptr != NULL && result == NULL) {
+ fprintf(stderr, testFmt, orig, result, testCase[i].truthValue.sptr);
+ return 1;
+ }
+ myassert(strcmp(result, testCase[i].truthValue.sptr) == 0, testFmt, orig, result, testCase[i].truthValue.sptr);
+ free(caseValue);
+ free(orig);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_num_chars_generic.c b/tests/test_str_num_chars_generic.c
new file mode 100644
index 0000000..b5ae6a5
--- /dev/null
+++ b/tests/test_str_num_chars_generic.c
@@ -0,0 +1,31 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case '%s': returned %d, expected %d\n";
+struct TestCase testCase[] = {
+ {.inputValue.unsigned_integer = 'a', .caseValue.sptr = "after the world stops spinning", .truthValue.signed_integer = 1},
+ {.inputValue.unsigned_integer = 'a', .caseValue.sptr = "apples exploded all over the place", .truthValue.signed_integer = 3},
+ {.inputValue.unsigned_integer = 'a', .caseValue.sptr = "a1a2a3a4a z!z@z#z$z a5a6a7a8a9", .truthValue.signed_integer = 10},
+ {.inputValue.unsigned_integer = 'a', .caseValue.sptr = "aAaA", .truthValue.signed_integer = 2},
+ {.inputValue.unsigned_integer = 'A', .caseValue.sptr = "aAaA", .truthValue.signed_integer = 2},
+ {.inputValue.unsigned_integer = 'b', .caseValue.sptr = "abracadabra brisket gumball", .truthValue.signed_integer = 4},
+ {.inputValue.unsigned_integer = 'b', .caseValue.sptr = "balloons are falling from the sky", .truthValue.signed_integer = 1},
+ {.inputValue.unsigned_integer = 'b', .caseValue.sptr = "mangled mangoes oxidize quickly", .truthValue.signed_integer = 0},
+ {.inputValue.unsigned_integer = 'b', .caseValue.sptr = "bBbB", .truthValue.signed_integer = 2},
+ {.inputValue.unsigned_integer = 'B', .caseValue.sptr = "bBbB", .truthValue.signed_integer = 2},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ int result = num_chars(testCase[i].caseValue.sptr, testCase[i].inputValue.unsigned_integer);
+ myassert(result == testCase[i].truthValue.signed_integer,
+ testFmt,
+ testCase[i].caseValue.sptr,
+ result,
+ testCase[i].truthValue.signed_integer);
+ }
+
+ return 0;
+}
diff --git a/tests/test_str_print_banner.c b/tests/test_str_print_banner.c
new file mode 100644
index 0000000..0ca09fd
--- /dev/null
+++ b/tests/test_str_print_banner.c
@@ -0,0 +1,43 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case %zu: '%s' is length %zu, expected %zu\n";
+const char *testFmtChars = "case %zu: '%s' got '%c' (pos: %zu), expected '%c'\n";
+
+int main(int argc, char *argv[]) {
+ const int max_banner = 'z';
+ const int max_banner_len = 80;
+ char buf[BUFSIZ] = {0,};
+ char *buffer = buf;
+ int stdout_save = 0;
+
+ fflush(stdout);
+ for (size_t i = 'A', letters = 'A'; i <= max_banner; i++, letters++) {
+ char letter[1];
+ size_t buffer_len = 0;
+
+ // Assign letter character
+ sprintf(letter, "%c", (int)letters);
+
+ // Redirect stdout
+ stdout_save = dup(STDOUT_FILENO);
+ freopen("/dev/null", "w", stdout);
+ setvbuf(stdout, buffer, _IOLBF, sizeof(buf));
+
+ // Do test
+ print_banner(letter, i);
+ fflush(stdout);
+
+ strip(buffer);
+ buffer_len = strlen(buffer);
+
+ myassert(buffer_len == i, testFmt, i, buffer, buffer_len, i);
+ for (size_t j = 0; j < buffer_len; j++) {
+ myassert(buffer[j] == (int)letters, testFmtChars, i, buffer, j, buffer[j], (int)letters, buffer[j]);
+ }
+
+ // Restore stdout
+ dup2(stdout_save, STDOUT_FILENO);
+ setvbuf(stdout, NULL, _IONBF, 0);
+ }
+} \ No newline at end of file
diff --git a/tests/test_str_split.c b/tests/test_str_split.c
new file mode 100644
index 0000000..58ef56f
--- /dev/null
+++ b/tests/test_str_split.c
@@ -0,0 +1,29 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "could not split '%s' with '%s'\n";
+struct TestCase testCase[] = {
+ {.inputValue.sptr = " ", .caseValue.str = "one two three", .truthValue.slptr = (char *[]){"one", "two", "three", NULL}},
+ {.inputValue.sptr = "|", .caseValue.str = "one|two|three", .truthValue.slptr = (char *[]){"one", "two", "three", NULL}},
+ {.inputValue.sptr = "a", .caseValue.str = "123a456a789", .truthValue.slptr = (char *[]){"123", "456", "789", NULL}},
+ {.inputValue.sptr = "b", .caseValue.str = "123a456b789", .truthValue.slptr = (char *[]){"123a456", "789", NULL}},
+ {.inputValue.sptr = NULL, .caseValue.str = "123a456a789", .truthValue.slptr = NULL},
+ {.inputValue.sptr = "b", .caseValue.sptr = NULL, .truthValue.slptr = NULL},
+ {.inputValue.sptr = NULL, .caseValue.sptr = NULL, .truthValue.slptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char **result = split(testCase[i].caseValue.str, testCase[i].inputValue.sptr);
+ if (testCase[i].truthValue.slptr == NULL && result == NULL) {
+ continue;
+ }
+
+ for (size_t part = 0; testCase[i].truthValue.slptr[part] != NULL; part++) {
+ myassert(strcmp(result[part], testCase[i].truthValue.slptr[part]) == 0, testFmt, testCase[i].caseValue.str, testCase[i].inputValue.sptr);
+ }
+ split_free(result);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_startswith.c b/tests/test_str_startswith.c
new file mode 100644
index 0000000..da25341
--- /dev/null
+++ b/tests/test_str_startswith.c
@@ -0,0 +1,22 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "'%s' does not start with '%s' (%d)\n";
+struct TestCase testCase[] = {
+ {.inputValue.sptr = "abra", .caseValue.sptr = "abracadabra brisket gumball", .truthValue.signed_integer = 1},
+ {.inputValue.sptr = "ball", .caseValue.sptr = "balloons are falling from the sky", .truthValue.signed_integer = 1},
+ {.inputValue.sptr = "mangle", .caseValue.sptr = "mangled mangoes oxidize quickly", .truthValue.signed_integer = 1},
+ {.inputValue.sptr = "b", .caseValue.sptr = "bBbB", .truthValue.signed_integer = 1},
+ {.inputValue.sptr = NULL, .caseValue.sptr = "bBbB", .truthValue.signed_integer = -1},
+ {.inputValue.sptr = "test", .caseValue.sptr = NULL, .truthValue.signed_integer = -1},
+ {.inputValue.sptr = NULL, .caseValue.sptr = NULL, .truthValue.signed_integer = -1},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ int result = startswith(testCase[i].caseValue.sptr, testCase[i].inputValue.sptr);
+ myassert(result == testCase[i].truthValue.signed_integer, testFmt, testCase[i].inputValue.str, testCase[i].truthValue.sptr, result);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_strchrdel.c b/tests/test_str_strchrdel.c
new file mode 100644
index 0000000..67a77db
--- /dev/null
+++ b/tests/test_str_strchrdel.c
@@ -0,0 +1,61 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case '%s': returned '%s', expected '%s'\n";
+struct TestCase testCase[] = {
+ {.inputValue.sptr = " ",
+ .caseValue.str = "after the world stops spinning\0",
+ .truthValue.sptr = "aftertheworldstopsspinning"},
+
+ {.inputValue.sptr = "a",
+ .caseValue.str = "apples exploded all over the place",
+ .truthValue.sptr = "pples exploded ll over the plce"},
+
+ {.inputValue.sptr = "123456789",
+ .caseValue.str = "a1a2a3a4a z!z@z#z$z a5a6a7a8a9",
+ .truthValue.sptr = "aaaaa z!z@z#z$z aaaaa"},
+
+ {.inputValue.sptr = "a",
+ .caseValue.str = "aAaA",
+ .truthValue.sptr = "AA"},
+
+ {.inputValue.sptr = "A",
+ .caseValue.str = "aAaA",
+ .truthValue.sptr = "aa"},
+
+ {.inputValue.sptr = "brisket",
+ .caseValue.str = "abracadabra brisket gumball",
+ .truthValue.sptr = "aacadaa gumall"},
+
+ {.inputValue.sptr = "b",
+ .caseValue.str = "balloons are falling from the sky",
+ .truthValue.sptr = "alloons are falling from the sky"},
+
+ {.inputValue.sptr = "ly",
+ .caseValue.str = "mangled mangoes oxidize quickly",
+ .truthValue.sptr = "manged mangoes oxidize quick"},
+
+ {.inputValue.sptr = NULL,
+ .caseValue.str = "bBbB",
+ .truthValue.sptr = "bBbB"},
+
+ {.inputValue.sptr = "B",
+ .caseValue.str = "\0",
+ .truthValue.sptr = ""},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char *orig = strdup(testCase[i].caseValue.str);
+ strchrdel(testCase[i].caseValue.str, testCase[i].inputValue.sptr);
+ myassert(strcmp(testCase[i].caseValue.str, testCase[i].truthValue.sptr) == 0,
+ testFmt,
+ orig,
+ testCase[i].caseValue.str,
+ testCase[i].truthValue.sptr);
+ free(orig);
+ }
+
+ return 0;
+}
diff --git a/tests/test_str_strchroff.c b/tests/test_str_strchroff.c
new file mode 100644
index 0000000..805a96d
--- /dev/null
+++ b/tests/test_str_strchroff.c
@@ -0,0 +1,31 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case '%s': returned %d, expected %d\n";
+struct TestCase testCase[] = {
+ {.inputValue.unsigned_integer = 'a', .caseValue.sptr = "after the world stops spinning", .truthValue.signed_integer = 0},
+ {.inputValue.unsigned_integer = 'p', .caseValue.sptr = "apples exploded all over the place", .truthValue.signed_integer = 1},
+ {.inputValue.unsigned_integer = '2', .caseValue.sptr = "a1a2a3a4a z!z@z#z$z a5a6a7a8a9", .truthValue.signed_integer = 3},
+ {.inputValue.unsigned_integer = 'a', .caseValue.sptr = "aAaA", .truthValue.signed_integer = 0},
+ {.inputValue.unsigned_integer = 'A', .caseValue.sptr = "aAaA", .truthValue.signed_integer = 1},
+ {.inputValue.unsigned_integer = 'g', .caseValue.sptr = "abracadabra brisket gumball", .truthValue.signed_integer = 20},
+ {.inputValue.unsigned_integer = 'r', .caseValue.sptr = "balloons are falling from the sky", .truthValue.signed_integer = 10},
+ {.inputValue.unsigned_integer = 'b', .caseValue.sptr = "mangled mangoes oxidize quickly", .truthValue.signed_integer = -1},
+ {.inputValue.unsigned_integer = 'b', .caseValue.sptr = "bBbB", .truthValue.signed_integer = 0},
+ {.inputValue.unsigned_integer = 'B', .caseValue.sptr = "bBbB", .truthValue.signed_integer = 1},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ int result = strchroff(testCase[i].caseValue.sptr, testCase[i].inputValue.unsigned_integer);
+ myassert(result == testCase[i].truthValue.signed_integer,
+ testFmt,
+ testCase[i].caseValue.sptr,
+ result,
+ testCase[i].truthValue.signed_integer);
+ }
+
+ return 0;
+}
diff --git a/tests/test_str_strdeldup.c b/tests/test_str_strdeldup.c
new file mode 100644
index 0000000..1efdeb7
--- /dev/null
+++ b/tests/test_str_strdeldup.c
@@ -0,0 +1,31 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case: (array){%s} expected '%s', returned '%s' \n";
+struct TestCase testCase[] = {
+ {.caseValue.slptr = (char *[]){"a", "a", "c", "d", "e", NULL}, .truthValue.sptr = "acde"},
+ {.caseValue.slptr = (char *[]){"a", "b", "b", "d", "e", NULL}, .truthValue.sptr = "abde"},
+ {.caseValue.slptr = (char *[]){"a", "b", "c", "c", "e", NULL}, .truthValue.sptr = "abce"},
+ {.caseValue.slptr = (char *[]){"a", "b", "c", "d", "e", NULL}, .truthValue.sptr = "abcde"},
+ {.caseValue.slptr = (char *[]){"e", "d", "c", "b", "a", NULL}, .truthValue.sptr = "edcba"},
+ {.caseValue.slptr = NULL, .truthValue.sptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char **result = strdeldup(testCase[i].caseValue.slptr);
+ if (testCase[i].truthValue.sptr == NULL && result == NULL) {
+ continue;
+ } else if (testCase[i].truthValue.sptr == NULL && result != NULL) {
+ fprintf(stderr, testFmt, array_to_string(testCase[i].caseValue.slptr, ", "), testCase[i].truthValue.sptr, array_to_string(result, ""));
+ return 1;
+ }
+ char *str_result = join(result, "");
+
+ myassert(strcmp(str_result, testCase[i].truthValue.sptr) == 0, testFmt, array_to_string(testCase[i].caseValue.slptr, ", "), testCase[i].truthValue.sptr, str_result);
+
+ free(str_result);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_strdelsuffix.c b/tests/test_str_strdelsuffix.c
new file mode 100644
index 0000000..0bc9c85
--- /dev/null
+++ b/tests/test_str_strdelsuffix.c
@@ -0,0 +1,24 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "could not remove '%s' from '%s', expecting '%s'\n";
+struct TestCase testCase[] = {
+ {.inputValue.sptr = "gumball", .caseValue.str = "abracadabra brisket gumball", .truthValue.sptr = "abracadabra brisket"},
+ {.inputValue.sptr = "y", .caseValue.str = "balloons are falling from the sky", .truthValue.sptr = "balloons are falling from the sk"},
+ {.inputValue.sptr = "ickly", .caseValue.str = "mangled mangoes oxidize quickly", .truthValue.sptr = "mangled mangoes oxidize qu"},
+ {.inputValue.sptr = "B", .caseValue.str = "bBbB", .truthValue.sptr = "bBb"},
+ {.inputValue.sptr = NULL, .caseValue.str = "bBbB", .truthValue.sptr = "bBbB"},
+ {.inputValue.sptr = "test", .caseValue.str = "\0", .truthValue.sptr = ""},
+ {.inputValue.sptr = NULL, .caseValue.str = "\0", .truthValue.sptr = ""},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char *orig = strdup(testCase[i].caseValue.str);
+ strdelsuffix(testCase[i].caseValue.str, testCase[i].inputValue.sptr);
+ myassert(strcmp(testCase[i].caseValue.str, testCase[i].truthValue.sptr) == 0, testFmt, testCase[i].inputValue.sptr, orig, testCase[i].truthValue.sptr);
+ free(orig);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_strip.c b/tests/test_str_strip.c
new file mode 100644
index 0000000..ea334a4
--- /dev/null
+++ b/tests/test_str_strip.c
@@ -0,0 +1,36 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case '%s': returned '%s', expected '%s'\n";
+struct TestCase testCase[] = {
+ {.caseValue.str = "four spaces ", .truthValue.sptr = "four spaces"},
+ {.caseValue.str = "one tab\t", .truthValue.sptr = "one tab"},
+ {.caseValue.str = "a new line\n", .truthValue.sptr = "a new line"},
+ {.caseValue.sptr = NULL, .truthValue.sptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char *caseValue = NULL;
+ char *orig = NULL;
+ char *result = NULL;
+
+ if (testCase[i].caseValue.sptr != NULL) {
+ caseValue = strdup(testCase[i].caseValue.str);
+ orig = strdup(caseValue);
+ result = strip(caseValue);
+ }
+
+ if (testCase[i].truthValue.sptr == NULL && result == NULL) {
+ continue;
+ } else if (testCase[i].truthValue.sptr != NULL && result == NULL) {
+ fprintf(stderr, testFmt, orig, result, testCase[i].truthValue.sptr);
+ return 1;
+ }
+ myassert(strcmp(result, testCase[i].truthValue.sptr) == 0, testFmt, orig, result, testCase[i].truthValue.sptr);
+ free(caseValue);
+ free(orig);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_strsort.c b/tests/test_str_strsort.c
new file mode 100644
index 0000000..fbec04b
--- /dev/null
+++ b/tests/test_str_strsort.c
@@ -0,0 +1,36 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case: (array){%s}: returned '%s', expected '%s'\n";
+struct TestCase testCase[] = {
+ {.inputValue.unsigned_integer = SPM_SORT_NUMERIC, .caseValue.slptr = (char *[]){"1", "100", "10", "10000", "1000", "0", NULL}, .truthValue.sptr = "0 1 10 100 1000 10000"},
+ {.inputValue.unsigned_integer = SPM_SORT_LEN_ASCENDING, .caseValue.slptr = (char *[]){"1", "100", "10", "10000", "1000", "0", NULL}, .truthValue.sptr = "1 0 10 100 1000 10000"}, // no QA?
+ {.inputValue.unsigned_integer = SPM_SORT_LEN_DESCENDING, .caseValue.slptr = (char *[]){"1", "100", "10", "10000", "1000", "0", NULL}, .truthValue.sptr = "10000 1000 100 10 1 0"},
+ {.inputValue.unsigned_integer = SPM_SORT_ALPHA, .caseValue.slptr = (char *[]){"c", "b", "a", NULL}, .truthValue.sptr = "a b c"},
+ {.inputValue.unsigned_integer = SPM_SORT_ALPHA, .caseValue.slptr = (char *[]){"a", "b", "c", NULL}, .truthValue.sptr = "a b c"},
+ {.inputValue.unsigned_integer = SPM_SORT_ALPHA, .caseValue.slptr = (char *[]){"3", "2", "1", NULL}, .truthValue.sptr = "1 2 3"},
+ {.inputValue.unsigned_integer = SPM_SORT_ALPHA, .caseValue.slptr = (char *[]){"1", "2", "3", NULL}, .truthValue.sptr = "1 2 3"},
+ {.inputValue.unsigned_integer = SPM_SORT_ALPHA, .caseValue.slptr = (char *[]){"package2", "package1", NULL}, .truthValue.sptr = "package1 package2"},
+ {.inputValue.unsigned_integer = SPM_SORT_ALPHA, .caseValue.slptr = (char *[]){"package1", "package2", NULL}, .truthValue.sptr = "package1 package2"},
+ {.inputValue.unsigned_integer = SPM_SORT_ALPHA, .caseValue.sptr = NULL, .truthValue.slptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char **array_orig = strdup_array(testCase[i].caseValue.slptr);
+ char **array_case = strdup_array(array_orig);
+
+ strsort(array_case, testCase[i].inputValue.unsigned_integer);
+ char *str_result = join(array_case, " ");
+
+ if (testCase[i].truthValue.sptr == NULL && str_result == NULL) {
+ continue;
+ }
+ myassert(strcmp(str_result, testCase[i].truthValue.sptr) == 0, testFmt, array_to_string(array_orig, ", "), str_result, testCase[i].truthValue.sptr);
+ free(str_result);
+ split_free(array_case);
+ split_free(array_orig);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_strstr_array.c b/tests/test_str_strstr_array.c
new file mode 100644
index 0000000..d2b7288
--- /dev/null
+++ b/tests/test_str_strstr_array.c
@@ -0,0 +1,28 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case: (array){%s} expected '%s', returned '%s' \n";
+struct TestCase testCase[] = {
+ {.inputValue.sptr = "abracadabra", .caseValue.slptr = (char *[]){"abracadabra", "brisket", "gumball", NULL}, .truthValue.sptr = "abracadabra"},
+ {.inputValue.sptr = "brisket", .caseValue.slptr = (char *[]){"abracadabra", "brisket", "gumball", NULL}, .truthValue.sptr = "brisket"},
+ {.inputValue.sptr = "gumball", .caseValue.slptr = (char *[]){"abracadabra", "brisket", "gumball", NULL}, .truthValue.sptr = "gumball"},
+ {.inputValue.sptr = "abrac", .caseValue.slptr = (char *[]){"abracadabra", "brisket", "gumball", NULL}, .truthValue.sptr = "abracadabra"},
+ {.inputValue.sptr = "sket", .caseValue.slptr = (char *[]){"abracadabra", "brisket", "gumball", NULL}, .truthValue.sptr = "brisket"},
+ {.inputValue.sptr = "ball", .caseValue.slptr = (char *[]){"abracadabra", "brisket", "gumball", NULL}, .truthValue.sptr = "gumball"},
+ {.inputValue.sptr = NULL, .caseValue.slptr = NULL, .truthValue.sptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char *result = strstr_array(testCase[i].caseValue.slptr, testCase[i].inputValue.sptr);
+ if (testCase[i].truthValue.sptr == NULL && result == NULL) {
+ continue;
+ } else if (testCase[i].truthValue.sptr == NULL && result != NULL) {
+ fprintf(stderr, testFmt, testCase[i].inputValue.str, testCase[i].truthValue.sptr, result);
+ return 1;
+ }
+ myassert(strcmp(result, testCase[i].truthValue.sptr) == 0, testFmt, array_to_string(testCase[i].caseValue.slptr, ", "), testCase[i].truthValue.sptr, result);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tests/test_str_substring_between.c b/tests/test_str_substring_between.c
new file mode 100644
index 0000000..0177068
--- /dev/null
+++ b/tests/test_str_substring_between.c
@@ -0,0 +1,28 @@
+#include "spm.h"
+#include "framework.h"
+
+const char *testFmt = "case '%s': returned '%s', expected '%s'\n";
+struct TestCase testCase[] = {
+ {.inputValue.sptr = "[]", .caseValue.str = "[one two three]", .truthValue.sptr = "one two three"},
+ {.inputValue.sptr = "..", .caseValue.str = ".[one].", .truthValue.sptr = "[one]"},
+ {.inputValue.sptr = "\'\'", .caseValue.str = ".['one'].", .truthValue.sptr = "one"},
+ {.inputValue.sptr = "@^", .caseValue.str = "abcdef@ghijkl^mnop@qrst^uvwxyz", .truthValue.sptr = "ghijkl"},
+ {.inputValue.sptr = "", .caseValue.sptr = NULL, .truthValue.sptr = NULL},
+ {.inputValue.sptr = NULL, .caseValue.sptr = NULL, .truthValue.sptr = NULL},
+};
+size_t numCases = sizeof(testCase) / sizeof(struct TestCase);
+
+int main(int argc, char *argv[]) {
+ for (size_t i = 0; i < numCases; i++) {
+ char *result = substring_between(testCase[i].caseValue.str, testCase[i].inputValue.sptr);
+ if (testCase[i].truthValue.sptr == NULL && result == NULL) {
+ continue;
+ } else if (testCase[i].truthValue.sptr != NULL && result == NULL) {
+ fprintf(stderr, testFmt, testCase[i].caseValue.str, result, testCase[i].truthValue.sptr);
+ return 1;
+ }
+ myassert(strcmp(result, testCase[i].truthValue.sptr) == 0, testFmt, testCase[i].caseValue.str, result, testCase[i].truthValue.sptr);
+ free(result);
+ }
+ return 0;
+} \ No newline at end of file