aboutsummaryrefslogtreecommitdiffstats
path: root/tests/src
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src')
-rw-r--r--tests/src/test_itoa.c99
-rw-r--r--tests/src/test_put.c197
-rw-r--r--tests/src/test_split.c234
-rw-r--r--tests/src/test_striteri.c105
-rw-r--r--tests/src/test_strjoin.c111
-rw-r--r--tests/src/test_strmapi.c108
-rw-r--r--tests/src/test_strtrim.c162
-rw-r--r--tests/src/test_substr.c135
8 files changed, 1151 insertions, 0 deletions
diff --git a/tests/src/test_itoa.c b/tests/src/test_itoa.c
new file mode 100644
index 0000000..17cafe3
--- /dev/null
+++ b/tests/src/test_itoa.c
@@ -0,0 +1,99 @@
+#include "libft.h"
+#include "test_utils.h"
+#include <limits.h>
+
+static void
+_s_test_itoa (void)
+{
+ int i;
+ char label[128];
+ char expected[64];
+
+ _s_section ("ft_itoa");
+
+ /* zero */
+ {
+ char *p = ft_itoa (0);
+ _s_check ("zero", p && strcmp (p, "0") == 0);
+ free (p);
+ }
+
+ /* positive */
+ {
+ char *p = ft_itoa (42);
+ _s_check ("positive", p && strcmp (p, "42") == 0);
+ free (p);
+ }
+
+ /* negative */
+ {
+ char *p = ft_itoa (-42);
+ _s_check ("negative", p && strcmp (p, "-42") == 0);
+ free (p);
+ }
+
+ /* INT_MAX */
+ {
+ char *p = ft_itoa (INT_MAX);
+ snprintf (expected, sizeof (expected), "%d", INT_MAX);
+ _s_check ("INT_MAX", p && strcmp (p, expected) == 0);
+ free (p);
+ }
+
+ /* INT_MIN */
+ {
+ char *p = ft_itoa (INT_MIN);
+ snprintf (expected, sizeof (expected), "%d", INT_MIN);
+ _s_check ("INT_MIN", p && strcmp (p, expected) == 0);
+ free (p);
+ }
+
+ /* single digit positive */
+ {
+ char *p = ft_itoa (7);
+ _s_check ("single digit", p && strcmp (p, "7") == 0);
+ free (p);
+ }
+
+ /* single digit negative */
+ {
+ char *p = ft_itoa (-1);
+ _s_check ("neg single digit", p && strcmp (p, "-1") == 0);
+ free (p);
+ }
+
+ /* powers of ten */
+ {
+ char *p;
+
+ p = ft_itoa (10);
+ _s_check ("10", p && strcmp (p, "10") == 0);
+ free (p);
+ p = ft_itoa (100);
+ _s_check ("100", p && strcmp (p, "100") == 0);
+ free (p);
+ p = ft_itoa (-1000);
+ _s_check ("-1000", p && strcmp (p, "-1000") == 0);
+ free (p);
+ }
+
+ /* randomized */
+ for (i = 0; i < _S_RAND_ITERS; i++)
+ {
+ int n = rand () - RAND_MAX / 2;
+ char *p = ft_itoa (n);
+ snprintf (expected, sizeof (expected), "%d", n);
+ snprintf (label, sizeof (label), "random n=%d", n);
+ _s_check (label, p && strcmp (p, expected) == 0);
+ free (p);
+ }
+}
+
+int
+main (void)
+{
+ srand (time (NULL));
+ _s_test_itoa ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/src/test_put.c b/tests/src/test_put.c
new file mode 100644
index 0000000..3c7f6dc
--- /dev/null
+++ b/tests/src/test_put.c
@@ -0,0 +1,197 @@
+#include "libft.h"
+#include "test_utils.h"
+#include <limits.h>
+
+/* ── helper: capture fd output into a buffer ──────────────────────── */
+
+static int
+_s_read_pipe (void (*fn) (int), char *buf, size_t bufsz)
+{
+ int fds[2];
+ ssize_t n;
+
+ if (pipe (fds) < 0)
+ return (-1);
+ fn (fds[1]);
+ close (fds[1]);
+ n = read (fds[0], buf, bufsz - 1);
+ close (fds[0]);
+ if (n < 0)
+ return (-1);
+ buf[n] = '\0';
+ return (n);
+}
+
+/* ======================================
+ * ft_putchar_fd
+ * ====================================== */
+
+static void
+_s_putchar_a (int fd)
+{
+ ft_putchar_fd ('a', fd);
+}
+static void
+_s_putchar_nl (int fd)
+{
+ ft_putchar_fd ('\n', fd);
+}
+static void
+_s_putchar_zero (int fd)
+{
+ ft_putchar_fd ('\0', fd);
+}
+
+static void
+_s_test_putchar_fd (void)
+{
+ char buf[64];
+
+ _s_section ("ft_putchar_fd");
+
+ _s_read_pipe (_s_putchar_a, buf, sizeof (buf));
+ _s_check ("char 'a'", strcmp (buf, "a") == 0);
+
+ _s_read_pipe (_s_putchar_nl, buf, sizeof (buf));
+ _s_check ("newline", strcmp (buf, "\n") == 0);
+
+ {
+ int n = _s_read_pipe (_s_putchar_zero, buf, sizeof (buf));
+ _s_check ("null byte", n == 1 && buf[0] == '\0');
+ }
+}
+
+/* ======================================
+ * ft_putstr_fd
+ * ====================================== */
+
+static void
+_s_putstr_hello (int fd)
+{
+ ft_putstr_fd ("hello", fd);
+}
+static void
+_s_putstr_empty (int fd)
+{
+ ft_putstr_fd ("", fd);
+}
+
+_S_CRASH_V (ft_putstr_null, ft_putstr_fd (NULL, 1))
+
+static void
+_s_test_putstr_fd (void)
+{
+ char buf[256];
+
+ _s_section ("ft_putstr_fd");
+
+ _s_check ("NULL crashes", _s_crashes (_s_crash_ft_putstr_null));
+
+ _s_read_pipe (_s_putstr_hello, buf, sizeof (buf));
+ _s_check ("hello", strcmp (buf, "hello") == 0);
+
+ {
+ int n = _s_read_pipe (_s_putstr_empty, buf, sizeof (buf));
+ _s_check ("empty", n == 0);
+ }
+}
+
+/* ======================================
+ * ft_putendl_fd
+ * ====================================== */
+
+static void
+_s_putendl_hello (int fd)
+{
+ ft_putendl_fd ("hello", fd);
+}
+static void
+_s_putendl_empty (int fd)
+{
+ ft_putendl_fd ("", fd);
+}
+
+_S_CRASH_V (ft_putendl_null, ft_putendl_fd (NULL, 1))
+
+static void
+_s_test_putendl_fd (void)
+{
+ char buf[256];
+
+ _s_section ("ft_putendl_fd");
+
+ _s_check ("NULL crashes", _s_crashes (_s_crash_ft_putendl_null));
+
+ _s_read_pipe (_s_putendl_hello, buf, sizeof (buf));
+ _s_check ("hello\\n", strcmp (buf, "hello\n") == 0);
+
+ _s_read_pipe (_s_putendl_empty, buf, sizeof (buf));
+ _s_check ("empty\\n", strcmp (buf, "\n") == 0);
+}
+
+/* ======================================
+ * ft_putnbr_fd
+ * ====================================== */
+
+static void
+_s_putnbr_0 (int fd)
+{
+ ft_putnbr_fd (0, fd);
+}
+static void
+_s_putnbr_42 (int fd)
+{
+ ft_putnbr_fd (42, fd);
+}
+static void
+_s_putnbr_neg (int fd)
+{
+ ft_putnbr_fd (-42, fd);
+}
+static void
+_s_putnbr_max (int fd)
+{
+ ft_putnbr_fd (INT_MAX, fd);
+}
+static void
+_s_putnbr_min (int fd)
+{
+ ft_putnbr_fd (INT_MIN, fd);
+}
+
+static void
+_s_test_putnbr_fd (void)
+{
+ char buf[64];
+ char expected[64];
+
+ _s_section ("ft_putnbr_fd");
+
+ _s_read_pipe (_s_putnbr_0, buf, sizeof (buf));
+ _s_check ("zero", strcmp (buf, "0") == 0);
+
+ _s_read_pipe (_s_putnbr_42, buf, sizeof (buf));
+ _s_check ("positive", strcmp (buf, "42") == 0);
+
+ _s_read_pipe (_s_putnbr_neg, buf, sizeof (buf));
+ _s_check ("negative", strcmp (buf, "-42") == 0);
+
+ _s_read_pipe (_s_putnbr_max, buf, sizeof (buf));
+ snprintf (expected, sizeof (expected), "%d", INT_MAX);
+ _s_check ("INT_MAX", strcmp (buf, expected) == 0);
+
+ _s_read_pipe (_s_putnbr_min, buf, sizeof (buf));
+ snprintf (expected, sizeof (expected), "%d", INT_MIN);
+ _s_check ("INT_MIN", strcmp (buf, expected) == 0);
+}
+
+int
+main (void)
+{
+ _s_test_putchar_fd ();
+ _s_test_putstr_fd ();
+ _s_test_putendl_fd ();
+ _s_test_putnbr_fd ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/src/test_split.c b/tests/src/test_split.c
new file mode 100644
index 0000000..55847a2
--- /dev/null
+++ b/tests/src/test_split.c
@@ -0,0 +1,234 @@
+#include "libft.h"
+#include "test_utils.h"
+
+_S_CRASH (ft_split_null, ft_split (NULL, ' '))
+
+static void
+_s_free_split (char **arr)
+{
+ size_t i;
+
+ if (!arr)
+ return;
+ i = 0;
+ while (arr[i])
+ free (arr[i++]);
+ free (arr);
+}
+
+static size_t
+_s_arr_len (char **arr)
+{
+ size_t n;
+
+ n = 0;
+ while (arr[n])
+ n++;
+ return (n);
+}
+
+static void
+_s_test_split (void)
+{
+ int i;
+ char label[128];
+
+ _s_section ("ft_split");
+
+ /* NULL crashes */
+ _s_check ("NULL crashes", _s_crashes (_s_crash_ft_split_null));
+
+ /* basic split */
+ {
+ char **arr = ft_split ("hello world foo", ' ');
+ _s_check ("basic count", arr && _s_arr_len (arr) == 3);
+ _s_check ("basic [0]", arr && strcmp (arr[0], "hello") == 0);
+ _s_check ("basic [1]", arr && strcmp (arr[1], "world") == 0);
+ _s_check ("basic [2]", arr && strcmp (arr[2], "foo") == 0);
+ _s_check ("basic NULL-term", arr && arr[3] == NULL);
+ _s_free_split (arr);
+ }
+
+ /* leading delimiters */
+ {
+ char **arr = ft_split (" hello", ' ');
+ _s_check ("leading delim count", arr && _s_arr_len (arr) == 1);
+ _s_check ("leading delim [0]", arr && strcmp (arr[0], "hello") == 0);
+ _s_free_split (arr);
+ }
+
+ /* trailing delimiters */
+ {
+ char **arr = ft_split ("hello ", ' ');
+ _s_check ("trailing delim count", arr && _s_arr_len (arr) == 1);
+ _s_check ("trailing delim [0]", arr && strcmp (arr[0], "hello") == 0);
+ _s_free_split (arr);
+ }
+
+ /* consecutive delimiters */
+ {
+ char **arr = ft_split ("a,,b,,c", ',');
+ _s_check ("consec count", arr && _s_arr_len (arr) == 3);
+ _s_check ("consec [0]", arr && strcmp (arr[0], "a") == 0);
+ _s_check ("consec [1]", arr && strcmp (arr[1], "b") == 0);
+ _s_check ("consec [2]", arr && strcmp (arr[2], "c") == 0);
+ _s_free_split (arr);
+ }
+
+ /* no delimiter in string */
+ {
+ char **arr = ft_split ("hello", ' ');
+ _s_check ("no delim count", arr && _s_arr_len (arr) == 1);
+ _s_check ("no delim [0]", arr && strcmp (arr[0], "hello") == 0);
+ _s_free_split (arr);
+ }
+
+ /* empty string */
+ {
+ char **arr = ft_split ("", ' ');
+ _s_check ("empty count", arr && _s_arr_len (arr) == 0);
+ _s_check ("empty NULL-term", arr && arr[0] == NULL);
+ _s_free_split (arr);
+ }
+
+ /* string is only delimiters */
+ {
+ char **arr = ft_split (" ", ' ');
+ _s_check ("only delims count", arr && _s_arr_len (arr) == 0);
+ _s_check ("only delims NULL-term", arr && arr[0] == NULL);
+ _s_free_split (arr);
+ }
+
+ /* single character string, is delimiter */
+ {
+ char **arr = ft_split (",", ',');
+ _s_check ("single delim count", arr && _s_arr_len (arr) == 0);
+ _s_free_split (arr);
+ }
+
+ /* single character string, not delimiter */
+ {
+ char **arr = ft_split ("a", ',');
+ _s_check ("single non-delim count", arr && _s_arr_len (arr) == 1);
+ _s_check ("single non-delim [0]", arr && strcmp (arr[0], "a") == 0);
+ _s_free_split (arr);
+ }
+
+ /* delimiter '\0' — whole string is one word */
+ {
+ char **arr = ft_split ("hello", '\0');
+ _s_check ("nul delim count", arr && _s_arr_len (arr) == 1);
+ _s_check ("nul delim [0]", arr && strcmp (arr[0], "hello") == 0);
+ _s_free_split (arr);
+ }
+
+ /* each word is independently allocated */
+ {
+ char **arr = ft_split ("a b c", ' ');
+ _s_check ("independent ptrs", arr && arr[0] != arr[1] && arr[1] != arr[2]);
+ _s_free_split (arr);
+ }
+
+ /* randomized: build string from words, split, verify */
+ for (i = 0; i < _S_RAND_ITERS; i++)
+ {
+ int nwords = rand () % 10 + 1;
+ int pads = rand () % 5;
+ char **words = malloc (nwords * sizeof (char *));
+ char *src;
+ char **arr;
+ size_t total;
+ int j, k;
+ int ok;
+
+ if (!words)
+ continue;
+
+ /* generate random words (letters only) */
+ total = 0;
+ ok = 1;
+ for (j = 0; j < nwords; j++)
+ {
+ int wlen = rand () % 20 + 1;
+ words[j] = malloc (wlen + 1);
+ if (!words[j])
+ {
+ ok = 0;
+ break;
+ }
+ for (k = 0; k < wlen; k++)
+ words[j][k] = 'A' + rand () % 26;
+ words[j][wlen] = '\0';
+ total += wlen;
+ }
+ if (!ok)
+ {
+ for (k = 0; k < j; k++)
+ free (words[k]);
+ free (words);
+ continue;
+ }
+
+ /* build: pads + word + delimiters + ... + pads */
+ total += (nwords - 1) + 2 * pads;
+ src = malloc (total + 1);
+ if (!src)
+ {
+ for (j = 0; j < nwords; j++)
+ free (words[j]);
+ free (words);
+ continue;
+ }
+
+ k = 0;
+ for (j = 0; j < pads; j++)
+ src[k++] = ',';
+ for (j = 0; j < nwords; j++)
+ {
+ size_t wlen = strlen (words[j]);
+ memcpy (src + k, words[j], wlen);
+ k += wlen;
+ if (j < nwords - 1)
+ src[k++] = ',';
+ }
+ for (j = 0; j < pads; j++)
+ src[k++] = ',';
+ src[k] = '\0';
+
+ arr = ft_split (src, ',');
+ snprintf (label, sizeof (label), "random nwords=%d pads=%d", nwords,
+ pads);
+ if (!arr || (int)_s_arr_len (arr) != nwords)
+ {
+ _s_check (label, 0);
+ }
+ else
+ {
+ int match = 1;
+ for (j = 0; j < nwords; j++)
+ {
+ if (strcmp (arr[j], words[j]) != 0)
+ {
+ match = 0;
+ break;
+ }
+ }
+ _s_check (label, match && arr[nwords] == NULL);
+ }
+
+ for (j = 0; j < nwords; j++)
+ free (words[j]);
+ free (words);
+ free (src);
+ _s_free_split (arr);
+ }
+}
+
+int
+main (void)
+{
+ srand (time (NULL));
+ _s_test_split ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/src/test_striteri.c b/tests/src/test_striteri.c
new file mode 100644
index 0000000..0874c02
--- /dev/null
+++ b/tests/src/test_striteri.c
@@ -0,0 +1,105 @@
+#include "libft.h"
+#include "test_utils.h"
+#include <ctype.h>
+
+_S_CRASH_V (ft_striteri_null, ft_striteri (NULL, NULL))
+
+static void
+_s_to_upper (unsigned int i, char *c)
+{
+ (void)i;
+ *c = toupper (*c);
+}
+
+static void
+_s_add_index (unsigned int i, char *c)
+{
+ *c = *c + i;
+}
+
+static void
+_s_test_striteri (void)
+{
+ int i;
+ char label[128];
+
+ _s_section ("ft_striteri");
+
+ /* NULL crashes */
+ _s_check ("NULL crashes", _s_crashes (_s_crash_ft_striteri_null));
+
+ /* basic: to uppercase in place */
+ {
+ char s[] = "hello";
+ ft_striteri (s, _s_to_upper);
+ _s_check ("to_upper", strcmp (s, "HELLO") == 0);
+ }
+
+ /* function receives correct index */
+ {
+ char s[] = "aaaa";
+ ft_striteri (s, _s_add_index);
+ _s_check ("index passed",
+ s[0] == 'a' && s[1] == 'b' && s[2] == 'c' && s[3] == 'd');
+ }
+
+ /* empty string: no crash, no change */
+ {
+ char s[] = "";
+ ft_striteri (s, _s_to_upper);
+ _s_check ("empty", strcmp (s, "") == 0);
+ }
+
+ /* single character */
+ {
+ char s[] = "a";
+ ft_striteri (s, _s_to_upper);
+ _s_check ("single char", strcmp (s, "A") == 0);
+ }
+
+ /* modifies in place (same pointer) */
+ {
+ char s[] = "hello";
+ char *orig = s;
+ ft_striteri (s, _s_to_upper);
+ _s_check ("in place", s == orig);
+ }
+
+ /* randomized: apply to_upper, compare with manual */
+ for (i = 0; i < _S_RAND_ITERS; i++)
+ {
+ int len = rand () % 200 + 1;
+ char *src = malloc (len + 1);
+ char *expected = malloc (len + 1);
+ int j;
+
+ if (!src || !expected)
+ {
+ free (src);
+ free (expected);
+ continue;
+ }
+ for (j = 0; j < len; j++)
+ {
+ src[j] = 'a' + rand () % 26;
+ expected[j] = toupper (src[j]);
+ }
+ src[len] = '\0';
+ expected[len] = '\0';
+
+ ft_striteri (src, _s_to_upper);
+ snprintf (label, sizeof (label), "random len=%d", len);
+ _s_check (label, strcmp (src, expected) == 0);
+ free (src);
+ free (expected);
+ }
+}
+
+int
+main (void)
+{
+ srand (time (NULL));
+ _s_test_striteri ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/src/test_strjoin.c b/tests/src/test_strjoin.c
new file mode 100644
index 0000000..023f84d
--- /dev/null
+++ b/tests/src/test_strjoin.c
@@ -0,0 +1,111 @@
+#include "libft.h"
+#include "test_utils.h"
+
+_S_CRASH (ft_strjoin_null_s1, ft_strjoin (NULL, "hello"))
+_S_CRASH (ft_strjoin_null_s2, ft_strjoin ("hello", NULL))
+_S_CRASH (ft_strjoin_null_both, ft_strjoin (NULL, NULL))
+
+static void
+_s_test_strjoin (void)
+{
+ int i;
+ char label[128];
+
+ _s_section ("ft_strjoin");
+
+ /* NULL crashes */
+ _s_check ("NULL s1 crashes", _s_crashes (_s_crash_ft_strjoin_null_s1));
+ _s_check ("NULL s2 crashes", _s_crashes (_s_crash_ft_strjoin_null_s2));
+ _s_check ("NULL both crashes", _s_crashes (_s_crash_ft_strjoin_null_both));
+
+ /* two normal strings */
+ {
+ char *p = ft_strjoin ("hello ", "world");
+ _s_check ("basic", p && strcmp (p, "hello world") == 0);
+ free (p);
+ }
+
+ /* first string empty */
+ {
+ char *p = ft_strjoin ("", "world");
+ _s_check ("s1 empty", p && strcmp (p, "world") == 0);
+ free (p);
+ }
+
+ /* second string empty */
+ {
+ char *p = ft_strjoin ("hello", "");
+ _s_check ("s2 empty", p && strcmp (p, "hello") == 0);
+ free (p);
+ }
+
+ /* both empty */
+ {
+ char *p = ft_strjoin ("", "");
+ _s_check ("both empty", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* returns independent copy */
+ {
+ char s1[] = "abc";
+ char s2[] = "def";
+ char *p = ft_strjoin (s1, s2);
+ _s_check ("independent ptr", p && p != s1 && p != s2);
+ s1[0] = 'X';
+ _s_check ("mutation safe", p[0] == 'a');
+ free (p);
+ }
+
+ /* randomized */
+ for (i = 0; i < _S_RAND_ITERS; i++)
+ {
+ int len1 = rand () % 200 + 1;
+ int len2 = rand () % 200 + 1;
+ char *s1 = malloc (len1 + 1);
+ char *s2 = malloc (len2 + 1);
+ char *expected;
+ char *p;
+ int j;
+
+ if (!s1 || !s2)
+ {
+ free (s1);
+ free (s2);
+ continue;
+ }
+ for (j = 0; j < len1; j++)
+ s1[j] = 'A' + rand () % 26;
+ s1[len1] = '\0';
+ for (j = 0; j < len2; j++)
+ s2[j] = 'a' + rand () % 26;
+ s2[len2] = '\0';
+
+ expected = malloc (len1 + len2 + 1);
+ if (!expected)
+ {
+ free (s1);
+ free (s2);
+ continue;
+ }
+ memcpy (expected, s1, len1);
+ memcpy (expected + len1, s2, len2 + 1);
+
+ p = ft_strjoin (s1, s2);
+ snprintf (label, sizeof (label), "random len1=%d len2=%d", len1, len2);
+ _s_check (label, p && strcmp (p, expected) == 0);
+ free (s1);
+ free (s2);
+ free (expected);
+ free (p);
+ }
+}
+
+int
+main (void)
+{
+ srand (time (NULL));
+ _s_test_strjoin ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/src/test_strmapi.c b/tests/src/test_strmapi.c
new file mode 100644
index 0000000..31dba65
--- /dev/null
+++ b/tests/src/test_strmapi.c
@@ -0,0 +1,108 @@
+#include "libft.h"
+#include "test_utils.h"
+#include <ctype.h>
+
+_S_CRASH (ft_strmapi_null, ft_strmapi (NULL, NULL))
+
+static char
+_s_to_upper (unsigned int i, char c)
+{
+ (void)i;
+ return (toupper (c));
+}
+
+static char
+_s_add_index (unsigned int i, char c)
+{
+ return (c + i);
+}
+
+static void
+_s_test_strmapi (void)
+{
+ int i;
+ char label[128];
+
+ _s_section ("ft_strmapi");
+
+ /* NULL crashes */
+ _s_check ("NULL crashes", _s_crashes (_s_crash_ft_strmapi_null));
+
+ /* basic: to uppercase */
+ {
+ char *p = ft_strmapi ("hello", _s_to_upper);
+ _s_check ("to_upper", p && strcmp (p, "HELLO") == 0);
+ free (p);
+ }
+
+ /* function receives correct index */
+ {
+ char *p = ft_strmapi ("aaaa", _s_add_index);
+ _s_check ("index passed",
+ p && p[0] == 'a' && p[1] == 'b' && p[2] == 'c' && p[3] == 'd');
+ free (p);
+ }
+
+ /* empty string */
+ {
+ char *p = ft_strmapi ("", _s_to_upper);
+ _s_check ("empty", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* returns independent copy */
+ {
+ char s[] = "hello";
+ char *p = ft_strmapi (s, _s_to_upper);
+ _s_check ("independent ptr", p && p != s);
+ _s_check ("original unchanged", strcmp (s, "hello") == 0);
+ free (p);
+ }
+
+ /* single character */
+ {
+ char *p = ft_strmapi ("a", _s_to_upper);
+ _s_check ("single char", p && strcmp (p, "A") == 0);
+ free (p);
+ }
+
+ /* randomized: apply to_upper, compare with manual */
+ for (i = 0; i < _S_RAND_ITERS; i++)
+ {
+ int len = rand () % 200 + 1;
+ char *src = malloc (len + 1);
+ char *expected = malloc (len + 1);
+ char *p;
+ int j;
+
+ if (!src || !expected)
+ {
+ free (src);
+ free (expected);
+ continue;
+ }
+ for (j = 0; j < len; j++)
+ {
+ src[j] = 'a' + rand () % 26;
+ expected[j] = toupper (src[j]);
+ }
+ src[len] = '\0';
+ expected[len] = '\0';
+
+ p = ft_strmapi (src, _s_to_upper);
+ snprintf (label, sizeof (label), "random len=%d", len);
+ _s_check (label, p && strcmp (p, expected) == 0);
+ free (src);
+ free (expected);
+ free (p);
+ }
+}
+
+int
+main (void)
+{
+ srand (time (NULL));
+ _s_test_strmapi ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/src/test_strtrim.c b/tests/src/test_strtrim.c
new file mode 100644
index 0000000..aa57ef7
--- /dev/null
+++ b/tests/src/test_strtrim.c
@@ -0,0 +1,162 @@
+#include "libft.h"
+#include "test_utils.h"
+
+_S_CRASH (ft_strtrim_null_s1, ft_strtrim (NULL, " "))
+_S_CRASH (ft_strtrim_null_set, ft_strtrim ("hello", NULL))
+_S_CRASH (ft_strtrim_null_both, ft_strtrim (NULL, NULL))
+
+static void
+_s_test_strtrim (void)
+{
+ int i;
+ char label[128];
+
+ _s_section ("ft_strtrim");
+
+ /* NULL crashes */
+ _s_check ("NULL s1 crashes", _s_crashes (_s_crash_ft_strtrim_null_s1));
+ _s_check ("NULL set crashes", _s_crashes (_s_crash_ft_strtrim_null_set));
+ _s_check ("NULL both crashes", _s_crashes (_s_crash_ft_strtrim_null_both));
+
+ /* trim spaces from both ends */
+ {
+ char *p = ft_strtrim (" hello ", " ");
+ _s_check ("spaces both ends", p && strcmp (p, "hello") == 0);
+ free (p);
+ }
+
+ /* trim multiple characters */
+ {
+ char *p = ft_strtrim ("xxhelloxx", "x");
+ _s_check ("single trim char", p && strcmp (p, "hello") == 0);
+ free (p);
+ }
+
+ /* trim set with multiple chars */
+ {
+ char *p = ft_strtrim (".-hello-.", ".-");
+ _s_check ("multi-char set", p && strcmp (p, "hello") == 0);
+ free (p);
+ }
+
+ /* nothing to trim */
+ {
+ char *p = ft_strtrim ("hello", " ");
+ _s_check ("nothing to trim", p && strcmp (p, "hello") == 0);
+ free (p);
+ }
+
+ /* everything trimmed */
+ {
+ char *p = ft_strtrim ("aaaa", "a");
+ _s_check ("all trimmed", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* empty string */
+ {
+ char *p = ft_strtrim ("", "abc");
+ _s_check ("empty s1", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* empty set */
+ {
+ char *p = ft_strtrim (" hello ", "");
+ _s_check ("empty set", p && strcmp (p, " hello ") == 0);
+ free (p);
+ }
+
+ /* trim only leading */
+ {
+ char *p = ft_strtrim ("xxhello", "x");
+ _s_check ("leading only", p && strcmp (p, "hello") == 0);
+ free (p);
+ }
+
+ /* trim only trailing */
+ {
+ char *p = ft_strtrim ("helloxx", "x");
+ _s_check ("trailing only", p && strcmp (p, "hello") == 0);
+ free (p);
+ }
+
+ /* set chars in the middle are preserved */
+ {
+ char *p = ft_strtrim (" hello world ", " ");
+ _s_check ("middle preserved", p && strcmp (p, "hello world") == 0);
+ free (p);
+ }
+
+ /* single character string, in set */
+ {
+ char *p = ft_strtrim ("x", "x");
+ _s_check ("single char trimmed", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* single character string, not in set */
+ {
+ char *p = ft_strtrim ("x", "y");
+ _s_check ("single char kept", p && strcmp (p, "x") == 0);
+ free (p);
+ }
+
+ /* returns independent copy */
+ {
+ char s1[] = "hello";
+ char *p = ft_strtrim (s1, "");
+ _s_check ("independent ptr", p && p != s1);
+ free (p);
+ }
+
+ /* randomized */
+ for (i = 0; i < _S_RAND_ITERS; i++)
+ {
+ int core_len = rand () % 100 + 1;
+ int pad_len = rand () % 20;
+ char *src;
+ char *p;
+ char *expected;
+ int j;
+
+ src = malloc (pad_len + core_len + pad_len + 1);
+ expected = malloc (core_len + 1);
+ if (!src || !expected)
+ {
+ free (src);
+ free (expected);
+ continue;
+ }
+
+ /* pad with spaces, core with letters */
+ for (j = 0; j < pad_len; j++)
+ src[j] = ' ';
+ for (j = 0; j < core_len; j++)
+ {
+ src[pad_len + j] = 'A' + rand () % 26;
+ expected[j] = src[pad_len + j];
+ }
+ expected[core_len] = '\0';
+ for (j = 0; j < pad_len; j++)
+ src[pad_len + core_len + j] = ' ';
+ src[pad_len + core_len + pad_len] = '\0';
+
+ p = ft_strtrim (src, " ");
+ snprintf (label, sizeof (label), "random core=%d pad=%d", core_len,
+ pad_len);
+ _s_check (label, p && strcmp (p, expected) == 0);
+ free (src);
+ free (expected);
+ free (p);
+ }
+}
+
+int
+main (void)
+{
+ srand (time (NULL));
+ _s_test_strtrim ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/src/test_substr.c b/tests/src/test_substr.c
new file mode 100644
index 0000000..30e59ce
--- /dev/null
+++ b/tests/src/test_substr.c
@@ -0,0 +1,135 @@
+#include "libft.h"
+#include "test_utils.h"
+
+_S_CRASH (ft_substr_null, ft_substr (NULL, 0, 5))
+
+static void
+_s_test_substr (void)
+{
+ int i;
+ char label[128];
+
+ _s_section ("ft_substr");
+
+ /* NULL crashes */
+ _s_check ("NULL crashes", _s_crashes (_s_crash_ft_substr_null));
+
+ /* basic substring from the middle */
+ {
+ char *p = ft_substr ("hello world", 6, 5);
+ _s_check ("middle", p && strcmp (p, "world") == 0);
+ free (p);
+ }
+
+ /* from the start */
+ {
+ char *p = ft_substr ("hello", 0, 3);
+ _s_check ("from start", p && strcmp (p, "hel") == 0);
+ free (p);
+ }
+
+ /* len larger than remaining string */
+ {
+ char *p = ft_substr ("hello", 2, 100);
+ _s_check ("len > remaining", p && strcmp (p, "llo") == 0);
+ free (p);
+ }
+
+ /* start beyond string length */
+ {
+ char *p = ft_substr ("hello", 10, 5);
+ _s_check ("start > slen", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* start == string length */
+ {
+ char *p = ft_substr ("hello", 5, 5);
+ _s_check ("start == slen", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* empty source string */
+ {
+ char *p = ft_substr ("", 0, 10);
+ _s_check ("empty src", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* len == 0 */
+ {
+ char *p = ft_substr ("hello", 0, 0);
+ _s_check ("len=0", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* full string copy */
+ {
+ char *p = ft_substr ("hello", 0, 5);
+ _s_check ("full copy", p && strcmp (p, "hello") == 0);
+ free (p);
+ }
+
+ /* single character */
+ {
+ char *p = ft_substr ("hello", 4, 1);
+ _s_check ("single char", p && strcmp (p, "o") == 0);
+ free (p);
+ }
+
+ /* returns independent copy */
+ {
+ char src[] = "hello";
+ char *p = ft_substr (src, 0, 5);
+ _s_check ("independent ptr", p && p != src);
+ free (p);
+ }
+
+ /* randomized */
+ for (i = 0; i < _S_RAND_ITERS; i++)
+ {
+ int slen = rand () % 200 + 1;
+ char *src = malloc (slen + 1);
+ unsigned int start;
+ size_t len;
+ char *p;
+ int j;
+
+ if (!src)
+ continue;
+ for (j = 0; j < slen; j++)
+ src[j] = 'A' + rand () % 26;
+ src[slen] = '\0';
+
+ start = rand () % (slen + 5);
+ len = rand () % (slen + 5);
+ p = ft_substr (src, start, len);
+
+ if (start >= (unsigned int)slen)
+ {
+ snprintf (label, sizeof (label), "random start=%u >= slen=%d", start,
+ slen);
+ _s_check (label, p && strcmp (p, "") == 0);
+ }
+ else
+ {
+ size_t remaining = slen - start;
+ size_t expected = remaining < len ? remaining : len;
+ snprintf (label, sizeof (label), "random start=%u len=%zu slen=%d",
+ start, len, slen);
+ _s_check (label, p && strlen (p) == expected
+ && strncmp (p, src + start, expected) == 0);
+ }
+ free (p);
+ free (src);
+ }
+}
+
+int
+main (void)
+{
+ srand (time (NULL));
+ _s_test_substr ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}