aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format1
-rw-r--r--.gitignore4
-rw-r--r--Makefile32
-rw-r--r--docs/libft.en.subject.pdfbin0 -> 1406827 bytes
-rw-r--r--ft_atoi.c26
-rw-r--r--ft_bzero.c7
-rw-r--r--ft_calloc.c19
-rw-r--r--ft_isalnum.c7
-rw-r--r--ft_isalpha.c7
-rw-r--r--ft_isascii.c7
-rw-r--r--ft_isdigit.c7
-rw-r--r--ft_isprint.c7
-rw-r--r--ft_memchr.c16
-rw-r--r--ft_memcmp.c19
-rw-r--r--ft_memcpy.c16
-rw-r--r--ft_memmove.c26
-rw-r--r--ft_memset.c12
-rw-r--r--ft_strchr.c7
-rw-r--r--ft_strdup.c16
-rw-r--r--ft_strlcat.c23
-rw-r--r--ft_strlcpy.c20
-rw-r--r--ft_strlen.c12
-rw-r--r--ft_strncmp.c16
-rw-r--r--ft_strnstr.c19
-rw-r--r--ft_strrchr.c18
-rw-r--r--ft_tolower.c9
-rw-r--r--ft_toupper.c9
-rw-r--r--libft.h106
-rw-r--r--tests/Makefile31
-rw-r--r--tests/test_alloc.c159
-rw-r--r--tests/test_atoi.c58
-rw-r--r--tests/test_case.c36
-rw-r--r--tests/test_cmp.c279
-rw-r--r--tests/test_is.c43
-rw-r--r--tests/test_mem.c296
-rw-r--r--tests/test_search.c285
-rw-r--r--tests/test_strl.c252
-rw-r--r--tests/test_strlen.c109
38 files changed, 2016 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..a6cc54a
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: GNU
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ef58cd4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.o
+*.a
+tests/test_*
+!tests/test_*.c
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..55e0d7b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,32 @@
+NAME = libft.a
+
+CC = cc
+CFLAGS = -Wall -Wextra -Werror
+
+SRCS = ft_isalpha.c ft_isdigit.c ft_isalnum.c ft_isascii.c ft_isprint.c \
+ ft_strlen.c ft_memset.c ft_bzero.c ft_memcpy.c ft_memmove.c \
+ ft_memchr.c ft_memcmp.c ft_strncmp.c \
+ ft_strlcpy.c ft_strlcat.c \
+ ft_strchr.c ft_strrchr.c ft_strnstr.c ft_atoi.c \
+ ft_calloc.c ft_strdup.c \
+ ft_toupper.c ft_tolower.c
+
+OBJS = $(SRCS:.c=.o)
+
+$(NAME): $(OBJS)
+ ar rcs $(NAME) $(OBJS)
+
+all: $(NAME)
+
+clean:
+ rm -f $(OBJS)
+
+fclean: clean
+ rm -f $(NAME)
+
+re: fclean all
+
+test: $(NAME)
+ $(MAKE) -C tests
+
+.PHONY: all clean fclean re test
diff --git a/docs/libft.en.subject.pdf b/docs/libft.en.subject.pdf
new file mode 100644
index 0000000..81978cc
--- /dev/null
+++ b/docs/libft.en.subject.pdf
Binary files differ
diff --git a/ft_atoi.c b/ft_atoi.c
new file mode 100644
index 0000000..2fe091a
--- /dev/null
+++ b/ft_atoi.c
@@ -0,0 +1,26 @@
+#include "libft.h"
+
+int
+ft_atoi (const char *nptr)
+{
+ int sign;
+ int result;
+
+ result = 0;
+ sign = 1;
+ // Skip isspace() characters: space, \t, \n, \v, \f, \r.
+ while (*nptr == ' ' || (*nptr >= '\t' && *nptr <= '\r'))
+ nptr++;
+ if (*nptr == '-' || *nptr == '+')
+ {
+ if (*nptr == '-')
+ sign = -1;
+ nptr++;
+ }
+ while (*nptr >= '0' && *nptr <= '9')
+ {
+ result = result * 10 + (*nptr - '0');
+ nptr++;
+ }
+ return (result * sign);
+}
diff --git a/ft_bzero.c b/ft_bzero.c
new file mode 100644
index 0000000..10f67bd
--- /dev/null
+++ b/ft_bzero.c
@@ -0,0 +1,7 @@
+#include "libft.h"
+
+void
+ft_bzero (void *s, size_t n)
+{
+ ft_memset (s, 0, n);
+}
diff --git a/ft_calloc.c b/ft_calloc.c
new file mode 100644
index 0000000..7726c64
--- /dev/null
+++ b/ft_calloc.c
@@ -0,0 +1,19 @@
+#include "libft.h"
+#include <stdlib.h>
+
+void *
+ft_calloc (size_t nmemb, size_t size)
+{
+ void *ptr;
+ size_t total;
+
+ // Detect multiplication overflow before allocating.
+ if (nmemb && size > (size_t)-1 / nmemb)
+ return (NULL);
+ total = nmemb * size;
+ ptr = malloc (total);
+ if (!ptr)
+ return (NULL);
+ ft_bzero (ptr, total);
+ return (ptr);
+}
diff --git a/ft_isalnum.c b/ft_isalnum.c
new file mode 100644
index 0000000..4b477f8
--- /dev/null
+++ b/ft_isalnum.c
@@ -0,0 +1,7 @@
+#include "libft.h"
+
+int
+ft_isalnum (int c)
+{
+ return (ft_isalpha (c) || ft_isdigit (c));
+}
diff --git a/ft_isalpha.c b/ft_isalpha.c
new file mode 100644
index 0000000..c19cf58
--- /dev/null
+++ b/ft_isalpha.c
@@ -0,0 +1,7 @@
+#include "libft.h"
+
+int
+ft_isalpha (int c)
+{
+ return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
+}
diff --git a/ft_isascii.c b/ft_isascii.c
new file mode 100644
index 0000000..f9e877e
--- /dev/null
+++ b/ft_isascii.c
@@ -0,0 +1,7 @@
+#include "libft.h"
+
+int
+ft_isascii (int c)
+{
+ return (c >= 0 && c <= 127);
+}
diff --git a/ft_isdigit.c b/ft_isdigit.c
new file mode 100644
index 0000000..43de53f
--- /dev/null
+++ b/ft_isdigit.c
@@ -0,0 +1,7 @@
+#include "libft.h"
+
+int
+ft_isdigit (int c)
+{
+ return (c >= '0' && c <= '9');
+}
diff --git a/ft_isprint.c b/ft_isprint.c
new file mode 100644
index 0000000..73964ff
--- /dev/null
+++ b/ft_isprint.c
@@ -0,0 +1,7 @@
+#include "libft.h"
+
+int
+ft_isprint (int c)
+{
+ return (c >= 32 && c <= 126);
+}
diff --git a/ft_memchr.c b/ft_memchr.c
new file mode 100644
index 0000000..08d5c3e
--- /dev/null
+++ b/ft_memchr.c
@@ -0,0 +1,16 @@
+#include "libft.h"
+
+void *
+ft_memchr (const void *s, int c, size_t n)
+{
+ const unsigned char *ptr;
+
+ ptr = s;
+ while (n--)
+ {
+ if (*ptr == (unsigned char)c)
+ return ((void *)ptr);
+ ptr++;
+ }
+ return (NULL);
+}
diff --git a/ft_memcmp.c b/ft_memcmp.c
new file mode 100644
index 0000000..ce6cc77
--- /dev/null
+++ b/ft_memcmp.c
@@ -0,0 +1,19 @@
+#include "libft.h"
+
+int
+ft_memcmp (const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *p1;
+ const unsigned char *p2;
+
+ p1 = s1;
+ p2 = s2;
+ while (n--)
+ {
+ if (*p1 != *p2)
+ return (*p1 - *p2);
+ p1++;
+ p2++;
+ }
+ return (0);
+}
diff --git a/ft_memcpy.c b/ft_memcpy.c
new file mode 100644
index 0000000..26c4f76
--- /dev/null
+++ b/ft_memcpy.c
@@ -0,0 +1,16 @@
+#include "libft.h"
+
+void *
+ft_memcpy (void *dest, const void *src, size_t n)
+{
+ unsigned char *dst_bytes;
+ const unsigned char *src_bytes;
+
+ if (!dest && !src)
+ return (dest);
+ dst_bytes = dest;
+ src_bytes = src;
+ while (n--)
+ *dst_bytes++ = *src_bytes++;
+ return (dest);
+}
diff --git a/ft_memmove.c b/ft_memmove.c
new file mode 100644
index 0000000..ace0d90
--- /dev/null
+++ b/ft_memmove.c
@@ -0,0 +1,26 @@
+#include "libft.h"
+
+void *
+ft_memmove (void *dest, const void *src, size_t n)
+{
+ unsigned char *dst_bytes;
+ const unsigned char *src_bytes;
+
+ if (!dest && !src)
+ return (dest);
+ dst_bytes = dest;
+ src_bytes = src;
+ if (dst_bytes > src_bytes)
+ {
+ dst_bytes += n;
+ src_bytes += n;
+ while (n--)
+ *--dst_bytes = *--src_bytes;
+ }
+ else
+ {
+ while (n--)
+ *dst_bytes++ = *src_bytes++;
+ }
+ return (dest);
+}
diff --git a/ft_memset.c b/ft_memset.c
new file mode 100644
index 0000000..5be8fe6
--- /dev/null
+++ b/ft_memset.c
@@ -0,0 +1,12 @@
+#include "libft.h"
+
+void *
+ft_memset (void *s, int c, size_t n)
+{
+ unsigned char *ptr;
+
+ ptr = s;
+ while (n--)
+ *ptr++ = (unsigned char)c;
+ return (s);
+}
diff --git a/ft_strchr.c b/ft_strchr.c
new file mode 100644
index 0000000..0952232
--- /dev/null
+++ b/ft_strchr.c
@@ -0,0 +1,7 @@
+#include "libft.h"
+
+char *
+ft_strchr (const char *s, int c)
+{
+ return (ft_memchr (s, c, ft_strlen (s) + 1));
+}
diff --git a/ft_strdup.c b/ft_strdup.c
new file mode 100644
index 0000000..3a6be31
--- /dev/null
+++ b/ft_strdup.c
@@ -0,0 +1,16 @@
+#include "libft.h"
+#include <stdlib.h>
+
+char *
+ft_strdup (const char *s)
+{
+ size_t len;
+ char *dup;
+
+ len = ft_strlen (s);
+ dup = malloc (len + 1);
+ if (!dup)
+ return (NULL);
+ ft_memcpy (dup, s, len + 1);
+ return (dup);
+}
diff --git a/ft_strlcat.c b/ft_strlcat.c
new file mode 100644
index 0000000..1274ba5
--- /dev/null
+++ b/ft_strlcat.c
@@ -0,0 +1,23 @@
+#include "libft.h"
+
+size_t
+ft_strlcat (char *dst, const char *src, size_t size)
+{
+ size_t dst_len;
+ size_t src_len;
+ size_t avail;
+
+ dst_len = ft_strlen (dst);
+ src_len = ft_strlen (src);
+ if (dst_len >= size)
+ return (size + src_len);
+ avail = size - dst_len - 1;
+ if (src_len < avail)
+ ft_memcpy (dst + dst_len, src, src_len + 1);
+ else
+ {
+ ft_memcpy (dst + dst_len, src, avail);
+ dst[size - 1] = '\0';
+ }
+ return (dst_len + src_len);
+}
diff --git a/ft_strlcpy.c b/ft_strlcpy.c
new file mode 100644
index 0000000..2611041
--- /dev/null
+++ b/ft_strlcpy.c
@@ -0,0 +1,20 @@
+#include "libft.h"
+
+size_t
+ft_strlcpy (char *dst, const char *src, size_t size)
+{
+ size_t src_len;
+
+ src_len = ft_strlen (src);
+ if (size > 0)
+ {
+ if (src_len < size)
+ ft_memcpy (dst, src, src_len + 1);
+ else
+ {
+ ft_memcpy (dst, src, size - 1);
+ dst[size - 1] = '\0';
+ }
+ }
+ return (src_len);
+}
diff --git a/ft_strlen.c b/ft_strlen.c
new file mode 100644
index 0000000..06b0aae
--- /dev/null
+++ b/ft_strlen.c
@@ -0,0 +1,12 @@
+#include "libft.h"
+
+size_t
+ft_strlen (const char *s)
+{
+ size_t i;
+
+ i = 0;
+ while (s[i])
+ i++;
+ return (i);
+}
diff --git a/ft_strncmp.c b/ft_strncmp.c
new file mode 100644
index 0000000..2fa1099
--- /dev/null
+++ b/ft_strncmp.c
@@ -0,0 +1,16 @@
+#include "libft.h"
+
+int
+ft_strncmp (const char *s1, const char *s2, size_t n)
+{
+ while (n--)
+ {
+ if ((unsigned char)*s1 != (unsigned char)*s2)
+ return ((unsigned char)*s1 - (unsigned char)*s2);
+ if (*s1 == '\0')
+ return (0);
+ s1++;
+ s2++;
+ }
+ return (0);
+}
diff --git a/ft_strnstr.c b/ft_strnstr.c
new file mode 100644
index 0000000..23ac891
--- /dev/null
+++ b/ft_strnstr.c
@@ -0,0 +1,19 @@
+#include "libft.h"
+
+char *
+ft_strnstr (const char *big, const char *little, size_t len)
+{
+ size_t llen;
+
+ if (*little == '\0')
+ return ((char *)big);
+ llen = ft_strlen (little);
+ while (*big && len >= llen)
+ {
+ if (ft_memcmp (big, little, llen) == 0)
+ return ((char *)big);
+ big++;
+ len--;
+ }
+ return (NULL);
+}
diff --git a/ft_strrchr.c b/ft_strrchr.c
new file mode 100644
index 0000000..8ec72d1
--- /dev/null
+++ b/ft_strrchr.c
@@ -0,0 +1,18 @@
+#include "libft.h"
+
+char *
+ft_strrchr (const char *s, int c)
+{
+ size_t len;
+
+ len = ft_strlen (s);
+ while (len > 0)
+ {
+ if (s[len] == (char)c)
+ return ((char *)s + len);
+ len--;
+ }
+ if (s[0] == (char)c)
+ return ((char *)s);
+ return (NULL);
+}
diff --git a/ft_tolower.c b/ft_tolower.c
new file mode 100644
index 0000000..52fbc94
--- /dev/null
+++ b/ft_tolower.c
@@ -0,0 +1,9 @@
+#include "libft.h"
+
+int
+ft_tolower (int c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return (c + ('a' - 'A'));
+ return (c);
+}
diff --git a/ft_toupper.c b/ft_toupper.c
new file mode 100644
index 0000000..e52e0fa
--- /dev/null
+++ b/ft_toupper.c
@@ -0,0 +1,9 @@
+#include "libft.h"
+
+int
+ft_toupper (int c)
+{
+ if (c >= 'a' && c <= 'z')
+ return (c - ('a' - 'A'));
+ return (c);
+}
diff --git a/libft.h b/libft.h
new file mode 100644
index 0000000..d57cd8d
--- /dev/null
+++ b/libft.h
@@ -0,0 +1,106 @@
+/**
+ * @file libft.h
+ * @brief Reimplementations of standard C library functions.
+ *
+ * Every function mirrors its libc counterpart unless noted otherwise.
+ * Functions that operate on raw memory interpret bytes as unsigned char.
+ * BSD extensions (strlcpy, strlcat, strnstr) follow the OpenBSD semantics.
+ */
+
+#ifndef LIBFT_H
+#define LIBFT_H
+
+#include <stddef.h>
+
+/* ======================================
+ * Character classification & conversion
+ * ====================================== */
+
+/** @brief Return non-zero if @p c is an alphabetic letter. */
+int ft_isalpha (int c);
+/** @brief Return non-zero if @p c is a decimal digit. */
+int ft_isdigit (int c);
+/** @brief Return non-zero if @p c is alphanumeric. */
+int ft_isalnum (int c);
+/** @brief Return non-zero if @p c is a 7-bit ASCII value. */
+int ft_isascii (int c);
+/** @brief Return non-zero if @p c is a printable character. */
+int ft_isprint (int c);
+/** @brief Convert @p c to uppercase if it is a lowercase letter. */
+int ft_toupper (int c);
+/** @brief Convert @p c to lowercase if it is an uppercase letter. */
+int ft_tolower (int c);
+
+/* ======================================
+ * String examination
+ * ====================================== */
+
+/** @brief Return the length of the string @p s. */
+size_t ft_strlen (const char *s);
+/**
+ * @brief Compare at most @p n bytes of @p s1 and @p s2.
+ * @return Negative, zero, or positive integer.
+ */
+int ft_strncmp (const char *s1, const char *s2, size_t n);
+/** @brief Return a pointer to the first occurrence of @p c in @p s. */
+char *ft_strchr (const char *s, int c);
+/** @brief Return a pointer to the last occurrence of @p c in @p s. */
+char *ft_strrchr (const char *s, int c);
+/**
+ * @brief Locate @p little in @p big, searching at most @p len bytes.
+ * @note BSD extension — not available in glibc.
+ */
+char *ft_strnstr (const char *big, const char *little, size_t len);
+/** @brief Convert the initial portion of @p nptr to int. */
+int ft_atoi (const char *nptr);
+
+/* ======================================
+ * String manipulation
+ * ====================================== */
+
+/**
+ * @brief Copy @p src into @p dst, NUL-terminating the result.
+ * @return Length of @p src.
+ * @note BSD extension — not available in glibc.
+ */
+size_t ft_strlcpy (char *dst, const char *src, size_t size);
+/**
+ * @brief Append @p src to @p dst, NUL-terminating the result.
+ * @return Intended total length (dst_len + src_len).
+ * @note BSD extension — not available in glibc.
+ */
+size_t ft_strlcat (char *dst, const char *src, size_t size);
+/** @brief Return a malloc'd duplicate of @p s. */
+char *ft_strdup (const char *s);
+
+/* ======================================
+ * Memory operations
+ * ====================================== */
+
+/** @brief Fill @p n bytes of @p s with the byte @p c. */
+void *ft_memset (void *s, int c, size_t n);
+/** @brief Zero @p n bytes starting at @p s. */
+void ft_bzero (void *s, size_t n);
+/** @brief Copy @p n bytes from @p src to @p dest (no overlap). */
+void *ft_memcpy (void *dest, const void *src, size_t n);
+/** @brief Copy @p n bytes from @p src to @p dest (overlap-safe). */
+void *ft_memmove (void *dest, const void *src, size_t n);
+/** @brief Scan @p n bytes of @p s for the byte @p c. */
+void *ft_memchr (const void *s, int c, size_t n);
+/**
+ * @brief Compare @p n bytes of @p s1 and @p s2.
+ * @return Negative, zero, or positive integer.
+ */
+int ft_memcmp (const void *s1, const void *s2, size_t n);
+
+/* ======================================
+ * Memory allocation
+ * ====================================== */
+
+/**
+ * @brief Allocate zeroed memory for @p nmemb elements of @p size bytes.
+ * @return NULL on overflow or allocation failure.
+ */
+void *ft_calloc (size_t nmemb, size_t size);
+
+#endif
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644
index 0000000..319fa22
--- /dev/null
+++ b/tests/Makefile
@@ -0,0 +1,31 @@
+CC = cc
+CFLAGS =
+LIB = ../libft.a
+
+TESTS = test_strlen test_is test_mem test_cmp test_case test_strl test_search \
+ test_atoi test_alloc
+
+all: $(TESTS)
+ @for t in $(TESTS); do \
+ echo "--- Running $$t ---"; \
+ ./$$t; \
+ done
+
+test_%: test_%.c $(LIB)
+ $(CC) $(CFLAGS) -o $@ $< $(LIB)
+
+# Tests comparing against BSD functions (strlcpy, strlcat, strnstr)
+# need -lbsd since these are not part of glibc by default.
+test_strl: test_strl.c $(LIB)
+ $(CC) $(CFLAGS) -o $@ $< $(LIB) -lbsd
+
+test_search: test_search.c $(LIB)
+ $(CC) $(CFLAGS) -o $@ $< $(LIB) -lbsd
+
+$(LIB):
+ $(MAKE) -C ..
+
+clean:
+ rm -f $(TESTS)
+
+.PHONY: all clean
diff --git a/tests/test_alloc.c b/tests/test_alloc.c
new file mode 100644
index 0000000..191fbbb
--- /dev/null
+++ b/tests/test_alloc.c
@@ -0,0 +1,159 @@
+#include "../libft.h"
+#include "test_utils.h"
+
+static void
+_s_ft_strdup_null (void)
+{
+ _s_sink = (size_t)ft_strdup (NULL);
+}
+static void
+_s_libc_strdup_null (void)
+{
+ _s_sink = (size_t)strdup (NULL);
+}
+
+/* ======================================
+ * calloc
+ * ====================================== */
+
+static void
+_s_test_calloc (void)
+{
+ int i;
+ char label[64];
+
+ printf ("-- calloc --\n");
+
+ /* zeroed memory */
+ {
+ char *ft_p = ft_calloc (100, 1);
+ char *libc_p = calloc (100, 1);
+ _s_check ("zeroed", ft_p && libc_p && memcmp (ft_p, libc_p, 100) == 0);
+ free (ft_p);
+ free (libc_p);
+ }
+
+ /* nmemb=0 */
+ {
+ void *p = ft_calloc (0, 10);
+ _s_check ("nmemb=0 not NULL", p != NULL);
+ free (p);
+ }
+
+ /* size=0 */
+ {
+ void *p = ft_calloc (10, 0);
+ _s_check ("size=0 not NULL", p != NULL);
+ free (p);
+ }
+
+ /* overflow protection */
+ {
+ void *p = ft_calloc ((size_t)-1, 2);
+ _s_check ("overflow returns NULL", p == NULL);
+ }
+
+ /* single byte */
+ {
+ unsigned char *p = ft_calloc (1, 1);
+ _s_check ("single byte zeroed", p && *p == 0);
+ free (p);
+ }
+
+ /* randomized: check all bytes are zero */
+ srand (time (NULL));
+ for (i = 0; i < 50; i++)
+ {
+ size_t nmemb = rand () % 500 + 1;
+ size_t size = rand () % 50 + 1;
+ unsigned char *ft_p = ft_calloc (nmemb, size);
+ unsigned char *libc_p = calloc (nmemb, size);
+ int ok = 1;
+ size_t j;
+ if (!ft_p || !libc_p)
+ {
+ ok = 0;
+ }
+ else
+ {
+ for (j = 0; j < nmemb * size; j++)
+ {
+ if (ft_p[j] != 0)
+ {
+ ok = 0;
+ break;
+ }
+ }
+ }
+ snprintf (label, sizeof (label), "random nmemb=%zu size=%zu", nmemb,
+ size);
+ _s_check (label, ok);
+ free (ft_p);
+ free (libc_p);
+ }
+}
+
+/* ======================================
+ * strdup
+ * ====================================== */
+
+static void
+_s_test_strdup (void)
+{
+ int i;
+ char label[64];
+
+ printf ("-- strdup --\n");
+
+ /* NULL */
+ _s_check_both_crash ("strdup NULL", _s_ft_strdup_null, _s_libc_strdup_null);
+
+ /* empty string */
+ {
+ char *p = ft_strdup ("");
+ _s_check ("empty", p && strcmp (p, "") == 0);
+ free (p);
+ }
+
+ /* returns independent copy */
+ {
+ char src[] = "hello";
+ char *p = ft_strdup (src);
+ _s_check ("independent copy", p && p != src && strcmp (p, src) == 0);
+ src[0] = 'X';
+ _s_check ("mutation safe", p[0] == 'h');
+ free (p);
+ }
+
+ /* randomized */
+ for (i = 0; i < 50; i++)
+ {
+ int len = rand () % 500 + 1;
+ char *src = malloc (len + 1);
+ int j;
+ char *ft_p;
+ char *libc_p;
+ if (!src)
+ continue;
+ for (j = 0; j < len; j++)
+ src[j] = 'A' + rand () % 26;
+ src[len] = '\0';
+ ft_p = ft_strdup (src);
+ libc_p = strdup (src);
+ snprintf (label, sizeof (label), "random len=%d", len);
+ _s_check (label, ft_p && libc_p && strcmp (ft_p, libc_p) == 0);
+ free (src);
+ free (ft_p);
+ free (libc_p);
+ }
+}
+
+int
+main (void)
+{
+ printf ("=== alloc functions ===\n");
+ _s_test_calloc ();
+ _s_test_strdup ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/test_atoi.c b/tests/test_atoi.c
new file mode 100644
index 0000000..196a081
--- /dev/null
+++ b/tests/test_atoi.c
@@ -0,0 +1,58 @@
+#include "../libft.h"
+#include "test_utils.h"
+#include <limits.h>
+
+static void
+_s_ft_atoi_null (void)
+{
+ _s_sink_i = ft_atoi (NULL);
+}
+static void
+_s_libc_atoi_null (void)
+{
+ _s_sink_i = atoi (NULL);
+}
+
+int
+main (void)
+{
+ int i;
+ char buf[64];
+ char label[64];
+
+ printf ("=== ft_atoi ===\n");
+
+ /* NULL */
+ _s_check_both_crash ("atoi NULL", _s_ft_atoi_null, _s_libc_atoi_null);
+
+ /* edge cases */
+ _s_check_eq_int ("zero", ft_atoi ("0"), atoi ("0"));
+ _s_check_eq_int ("INT_MAX", ft_atoi ("2147483647"), atoi ("2147483647"));
+ _s_check_eq_int ("INT_MIN", ft_atoi ("-2147483648"), atoi ("-2147483648"));
+ _s_check_eq_int ("negative", ft_atoi ("-42"), atoi ("-42"));
+ _s_check_eq_int ("explicit +", ft_atoi ("+42"), atoi ("+42"));
+ _s_check_eq_int ("leading spaces", ft_atoi (" 42"), atoi (" 42"));
+ _s_check_eq_int ("leading tabs", ft_atoi ("\t\n\v\f\r 42"),
+ atoi ("\t\n\v\f\r 42"));
+ _s_check_eq_int ("trailing chars", ft_atoi ("42abc"), atoi ("42abc"));
+ _s_check_eq_int ("empty string", ft_atoi (""), atoi (""));
+ _s_check_eq_int ("only spaces", ft_atoi (" "), atoi (" "));
+ _s_check_eq_int ("only sign", ft_atoi ("-"), atoi ("-"));
+ _s_check_eq_int ("sign then space", ft_atoi ("- 42"), atoi ("- 42"));
+ _s_check_eq_int ("double sign", ft_atoi ("--42"), atoi ("--42"));
+ _s_check_eq_int ("space between", ft_atoi ("4 2"), atoi ("4 2"));
+ _s_check_eq_int ("leading zeros", ft_atoi ("00042"), atoi ("00042"));
+
+ /* randomized */
+ srand (time (NULL));
+ for (i = 0; i < 50; i++)
+ {
+ int v = rand () - RAND_MAX / 2;
+ snprintf (buf, sizeof (buf), "%d", v);
+ snprintf (label, sizeof (label), "random %s", buf);
+ _s_check_eq_int (label, ft_atoi (buf), atoi (buf));
+ }
+
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/test_case.c b/tests/test_case.c
new file mode 100644
index 0000000..44b567a
--- /dev/null
+++ b/tests/test_case.c
@@ -0,0 +1,36 @@
+#include "../libft.h"
+#include "test_utils.h"
+#include <ctype.h>
+
+static void
+_s_test_func (const char *name, int (*ft) (int), int (*libc) (int))
+{
+ int i;
+ int ok;
+
+ ok = 1;
+ for (i = -1; i <= 255; i++)
+ {
+ if (ft (i) != libc (i))
+ {
+ printf (" FAIL %s(%d): ft=%d libc=%d\n", name, i, ft (i), libc (i));
+ _s_fail++;
+ ok = 0;
+ }
+ }
+ if (ok)
+ {
+ printf (" PASS %s (all -1..255)\n", name);
+ _s_pass++;
+ }
+}
+
+int
+main (void)
+{
+ printf ("=== case functions ===\n");
+ _s_test_func ("ft_toupper", ft_toupper, toupper);
+ _s_test_func ("ft_tolower", ft_tolower, tolower);
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/test_cmp.c b/tests/test_cmp.c
new file mode 100644
index 0000000..eea0aea
--- /dev/null
+++ b/tests/test_cmp.c
@@ -0,0 +1,279 @@
+#include "../libft.h"
+#include "test_utils.h"
+
+static void
+_s_ft_memchr_null (void)
+{
+ _s_sink = (size_t)ft_memchr (NULL, 'a', 10);
+}
+static void
+_s_libc_memchr_null (void)
+{
+ _s_sink = (size_t)memchr (NULL, 'a', 10);
+}
+static void
+_s_ft_memcmp_null_s1 (void)
+{
+ _s_sink_i = ft_memcmp (NULL, "abc", 3);
+}
+static void
+_s_libc_memcmp_null_s1 (void)
+{
+ _s_sink_i = memcmp (NULL, "abc", 3);
+}
+static void
+_s_ft_memcmp_null_s2 (void)
+{
+ _s_sink_i = ft_memcmp ("abc", NULL, 3);
+}
+static void
+_s_libc_memcmp_null_s2 (void)
+{
+ _s_sink_i = memcmp ("abc", NULL, 3);
+}
+static void
+_s_ft_strncmp_null_s1 (void)
+{
+ _s_sink_i = ft_strncmp (NULL, "abc", 3);
+}
+static void
+_s_libc_strncmp_null_s1 (void)
+{
+ _s_sink_i = strncmp (NULL, "abc", 3);
+}
+static void
+_s_ft_strncmp_null_s2 (void)
+{
+ _s_sink_i = ft_strncmp ("abc", NULL, 3);
+}
+static void
+_s_libc_strncmp_null_s2 (void)
+{
+ _s_sink_i = strncmp ("abc", NULL, 3);
+}
+
+/* ======================================
+ * memchr
+ * ====================================== */
+
+static void
+_s_test_memchr (void)
+{
+ char buf[] = "Hello, World!";
+ char all[256];
+ int i;
+ char label[64];
+
+ printf ("-- memchr --\n");
+
+ /* NULL */
+ _s_check_both_crash ("memchr NULL", _s_ft_memchr_null, _s_libc_memchr_null);
+
+ /* find existing char */
+ _s_check ("find 'W'", ft_memchr (buf, 'W', 13) == memchr (buf, 'W', 13));
+
+ /* find first byte */
+ _s_check ("find 'H'", ft_memchr (buf, 'H', 13) == memchr (buf, 'H', 13));
+
+ /* find last byte */
+ _s_check ("find '!'", ft_memchr (buf, '!', 13) == memchr (buf, '!', 13));
+
+ /* not found */
+ _s_check ("not found 'z'",
+ ft_memchr (buf, 'z', 13) == memchr (buf, 'z', 13));
+
+ /* n=0 */
+ _s_check ("n=0", ft_memchr (buf, 'H', 0) == NULL);
+
+ /* char beyond n */
+ _s_check ("beyond n", ft_memchr (buf, '!', 5) == memchr (buf, '!', 5));
+
+ /* search for null byte */
+ _s_check ("find '\\0'", ft_memchr (buf, '\0', 14) == memchr (buf, '\0', 14));
+
+ /* int truncation to unsigned char */
+ _s_check ("int truncation",
+ ft_memchr (buf, 'H' + 256, 13) == memchr (buf, 'H' + 256, 13));
+
+ /* all byte values */
+ for (i = 0; i < 256; i++)
+ all[i] = i;
+ for (i = 0; i < 256; i++)
+ {
+ snprintf (label, sizeof (label), "byte %d", i);
+ _s_check (label, ft_memchr (all, i, 256) == memchr (all, i, 256));
+ }
+
+ /* randomized */
+ srand (time (NULL));
+ for (i = 0; i < 50; i++)
+ {
+ unsigned char rnd[256];
+ int len = rand () % 256 + 1;
+ int c = rand () % 256;
+ int j;
+ for (j = 0; j < len; j++)
+ rnd[j] = rand () % 256;
+ snprintf (label, sizeof (label), "random len=%d c=%d", len, c);
+ _s_check (label, ft_memchr (rnd, c, len) == memchr (rnd, c, len));
+ }
+}
+
+/* ======================================
+ * memcmp
+ * ====================================== */
+
+static void
+_s_test_memcmp (void)
+{
+ int i;
+ unsigned char a[256];
+ unsigned char b[256];
+ size_t len;
+ int pos;
+ char label[64];
+
+ printf ("-- memcmp --\n");
+
+ /* NULL */
+ _s_check_both_crash ("memcmp NULL s1", _s_ft_memcmp_null_s1,
+ _s_libc_memcmp_null_s1);
+ _s_check_both_crash ("memcmp NULL s2", _s_ft_memcmp_null_s2,
+ _s_libc_memcmp_null_s2);
+
+ /* equal */
+ _s_check ("equal", _s_sign (ft_memcmp ("abc", "abc", 3))
+ == _s_sign (memcmp ("abc", "abc", 3)));
+
+ /* first less */
+ _s_check ("less", _s_sign (ft_memcmp ("abc", "abd", 3))
+ == _s_sign (memcmp ("abc", "abd", 3)));
+
+ /* first greater */
+ _s_check ("greater", _s_sign (ft_memcmp ("abd", "abc", 3))
+ == _s_sign (memcmp ("abd", "abc", 3)));
+
+ /* n=0 */
+ _s_check ("n=0", _s_sign (ft_memcmp ("abc", "xyz", 0))
+ == _s_sign (memcmp ("abc", "xyz", 0)));
+
+ /* difference at last byte */
+ _s_check ("diff at end", _s_sign (ft_memcmp ("abcd", "abce", 4))
+ == _s_sign (memcmp ("abcd", "abce", 4)));
+
+ /* unsigned comparison: 0 vs 200 */
+ {
+ unsigned char x[] = { 0 };
+ unsigned char y[] = { 200 };
+ _s_check ("unsigned 0 vs 200",
+ _s_sign (ft_memcmp (x, y, 1)) == _s_sign (memcmp (x, y, 1)));
+ }
+
+ /* randomized */
+ srand (time (NULL));
+ for (i = 0; i < 50; i++)
+ {
+ len = rand () % 255 + 1;
+ for (pos = 0; pos < (int)len; pos++)
+ a[pos] = b[pos] = rand () % 256;
+ /* introduce a random difference sometimes */
+ if (i % 2 == 0)
+ {
+ pos = rand () % len;
+ b[pos] = (a[pos] + 1 + rand () % 255) % 256;
+ }
+ snprintf (label, sizeof (label), "random len=%zu", len);
+ _s_check (label, _s_sign (ft_memcmp (a, b, len))
+ == _s_sign (memcmp (a, b, len)));
+ }
+}
+
+/* ======================================
+ * strncmp
+ * ====================================== */
+
+static void
+_s_test_strncmp (void)
+{
+ int i;
+ char a[128];
+ char b[128];
+ int len;
+ char label[64];
+
+ printf ("-- strncmp --\n");
+
+ /* NULL */
+ _s_check_both_crash ("strncmp NULL s1", _s_ft_strncmp_null_s1,
+ _s_libc_strncmp_null_s1);
+ _s_check_both_crash ("strncmp NULL s2", _s_ft_strncmp_null_s2,
+ _s_libc_strncmp_null_s2);
+
+ /* equal strings */
+ _s_check ("equal", _s_sign (ft_strncmp ("abc", "abc", 3))
+ == _s_sign (strncmp ("abc", "abc", 3)));
+
+ /* less */
+ _s_check ("less", _s_sign (ft_strncmp ("abc", "abd", 3))
+ == _s_sign (strncmp ("abc", "abd", 3)));
+
+ /* greater */
+ _s_check ("greater", _s_sign (ft_strncmp ("abd", "abc", 3))
+ == _s_sign (strncmp ("abd", "abc", 3)));
+
+ /* n=0 */
+ _s_check ("n=0", _s_sign (ft_strncmp ("abc", "xyz", 0))
+ == _s_sign (strncmp ("abc", "xyz", 0)));
+
+ /* n larger than strings */
+ _s_check ("n > len", _s_sign (ft_strncmp ("abc", "abc", 100))
+ == _s_sign (strncmp ("abc", "abc", 100)));
+
+ /* difference beyond n */
+ _s_check ("diff beyond n", _s_sign (ft_strncmp ("abcX", "abcY", 3))
+ == _s_sign (strncmp ("abcX", "abcY", 3)));
+
+ /* empty strings */
+ _s_check ("both empty",
+ _s_sign (ft_strncmp ("", "", 5)) == _s_sign (strncmp ("", "", 5)));
+
+ /* one empty */
+ _s_check ("s1 empty", _s_sign (ft_strncmp ("", "a", 5))
+ == _s_sign (strncmp ("", "a", 5)));
+ _s_check ("s2 empty", _s_sign (ft_strncmp ("a", "", 5))
+ == _s_sign (strncmp ("a", "", 5)));
+
+ /* different lengths, equal prefix */
+ _s_check ("shorter s1", _s_sign (ft_strncmp ("ab", "abc", 5))
+ == _s_sign (strncmp ("ab", "abc", 5)));
+
+ /* unsigned comparison */
+ _s_check ("unsigned", _s_sign (ft_strncmp ("\xff", "\x01", 1))
+ == _s_sign (strncmp ("\xff", "\x01", 1)));
+
+ /* randomized */
+ for (i = 0; i < 50; i++)
+ {
+ len = rand () % 64 + 1;
+ for (int j = 0; j < len; j++)
+ a[j] = b[j] = 'A' + rand () % 26;
+ a[len] = '\0';
+ b[len] = '\0';
+ if (i % 2 == 0)
+ b[rand () % len] = 'A' + rand () % 26;
+ snprintf (label, sizeof (label), "random n=%d", len);
+ _s_check (label, _s_sign (ft_strncmp (a, b, len))
+ == _s_sign (strncmp (a, b, len)));
+ }
+}
+
+int
+main (void)
+{
+ printf ("=== comparison functions ===\n");
+ _s_test_memchr ();
+ _s_test_memcmp ();
+ _s_test_strncmp ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/test_is.c b/tests/test_is.c
new file mode 100644
index 0000000..1af5d40
--- /dev/null
+++ b/tests/test_is.c
@@ -0,0 +1,43 @@
+#include "../libft.h"
+#include "test_utils.h"
+#include <ctype.h>
+
+static void
+_s_test_func (const char *name, int (*ft) (int), int (*libc) (int))
+{
+ int i;
+ int ft_r;
+ int libc_r;
+ int ok;
+
+ ok = 1;
+ for (i = -1; i <= 255; i++)
+ {
+ ft_r = !!ft (i);
+ libc_r = !!libc (i);
+ if (ft_r != libc_r)
+ {
+ printf (" FAIL %s(%d): ft=%d libc=%d\n", name, i, ft_r, libc_r);
+ _s_fail++;
+ ok = 0;
+ }
+ }
+ if (ok)
+ {
+ printf (" PASS %s (all -1..255)\n", name);
+ _s_pass++;
+ }
+}
+
+int
+main (void)
+{
+ printf ("=== is* functions ===\n");
+ _s_test_func ("ft_isalpha", ft_isalpha, isalpha);
+ _s_test_func ("ft_isdigit", ft_isdigit, isdigit);
+ _s_test_func ("ft_isalnum", ft_isalnum, isalnum);
+ _s_test_func ("ft_isascii", ft_isascii, isascii);
+ _s_test_func ("ft_isprint", ft_isprint, isprint);
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/test_mem.c b/tests/test_mem.c
new file mode 100644
index 0000000..adbe12d
--- /dev/null
+++ b/tests/test_mem.c
@@ -0,0 +1,296 @@
+#include "../libft.h"
+#include "test_utils.h"
+#include <strings.h>
+
+static void
+_s_ft_memset_null (void)
+{
+ _s_sink = (size_t)ft_memset (NULL, 'A', 10);
+}
+static void
+_s_libc_memset_null (void)
+{
+ _s_sink = (size_t)memset (NULL, 'A', 10);
+}
+static void
+_s_ft_bzero_null (void)
+{
+ ft_bzero (NULL, 10);
+}
+static void
+_s_libc_bzero_null (void)
+{
+ bzero (NULL, 10);
+}
+static void
+_s_ft_memcpy_null_dst (void)
+{
+ char buf[10];
+ _s_sink = (size_t)ft_memcpy (NULL, buf, 10);
+}
+static void
+_s_libc_memcpy_null_dst (void)
+{
+ char buf[10];
+ _s_sink = (size_t)memcpy (NULL, buf, 10);
+}
+static void
+_s_ft_memcpy_null_src (void)
+{
+ char buf[10];
+ _s_sink = (size_t)ft_memcpy (buf, NULL, 10);
+}
+static void
+_s_libc_memcpy_null_src (void)
+{
+ char buf[10];
+ _s_sink = (size_t)memcpy (buf, NULL, 10);
+}
+static void
+_s_ft_memmove_null_dst (void)
+{
+ char buf[10];
+ _s_sink = (size_t)ft_memmove (NULL, buf, 10);
+}
+static void
+_s_libc_memmove_null_dst (void)
+{
+ char buf[10];
+ _s_sink = (size_t)memmove (NULL, buf, 10);
+}
+static void
+_s_ft_memmove_null_src (void)
+{
+ char buf[10];
+ _s_sink = (size_t)ft_memmove (buf, NULL, 10);
+}
+static void
+_s_libc_memmove_null_src (void)
+{
+ char buf[10];
+ _s_sink = (size_t)memmove (buf, NULL, 10);
+}
+
+/* ======================================
+ * memset
+ * ====================================== */
+
+static void
+_s_test_memset (void)
+{
+ char ft_buf[256];
+ char libc_buf[256];
+ int i;
+ int c;
+ size_t len;
+ void *ret;
+ char label[64];
+
+ printf ("-- memset --\n");
+
+ /* NULL */
+ _s_check_both_crash ("memset NULL", _s_ft_memset_null, _s_libc_memset_null);
+
+ /* zero length */
+ memset (ft_buf, 'X', 256);
+ memset (libc_buf, 'X', 256);
+ ft_memset (ft_buf, 'A', 0);
+ memset (libc_buf, 'A', 0);
+ _s_check ("n=0", memcmp (ft_buf, libc_buf, 256) == 0);
+
+ /* return value */
+ ret = ft_memset (ft_buf, 'B', 10);
+ _s_check ("return value", ret == ft_buf);
+
+ /* randomized */
+ srand (time (NULL));
+ for (i = 0; i < 50; i++)
+ {
+ c = rand () % 256;
+ len = rand () % 256;
+ ft_memset (ft_buf, c, len);
+ memset (libc_buf, c, len);
+ snprintf (label, sizeof (label), "random c=%d len=%zu", c, len);
+ _s_check (label, memcmp (ft_buf, libc_buf, len) == 0);
+ }
+}
+
+/* ======================================
+ * bzero
+ * ====================================== */
+
+static void
+_s_test_bzero (void)
+{
+ char ft_buf[256];
+ char libc_buf[256];
+ int i;
+ size_t len;
+ char label[64];
+
+ printf ("-- bzero --\n");
+
+ /* NULL */
+ _s_check_both_crash ("bzero NULL", _s_ft_bzero_null, _s_libc_bzero_null);
+
+ /* zero length */
+ memset (ft_buf, 'X', 256);
+ memset (libc_buf, 'X', 256);
+ ft_bzero (ft_buf, 0);
+ bzero (libc_buf, 0);
+ _s_check ("n=0", memcmp (ft_buf, libc_buf, 256) == 0);
+
+ /* full clear */
+ memset (ft_buf, 'X', 256);
+ memset (libc_buf, 'X', 256);
+ ft_bzero (ft_buf, 256);
+ bzero (libc_buf, 256);
+ _s_check ("n=256", memcmp (ft_buf, libc_buf, 256) == 0);
+
+ /* randomized */
+ for (i = 0; i < 50; i++)
+ {
+ len = rand () % 256;
+ memset (ft_buf, 'Z', 256);
+ memset (libc_buf, 'Z', 256);
+ ft_bzero (ft_buf, len);
+ bzero (libc_buf, len);
+ snprintf (label, sizeof (label), "random len=%zu", len);
+ _s_check (label, memcmp (ft_buf, libc_buf, 256) == 0);
+ }
+}
+
+/* ======================================
+ * memcpy
+ * ====================================== */
+
+static void
+_s_test_memcpy (void)
+{
+ char src[256];
+ char ft_dst[256];
+ char libc_dst[256];
+ int i;
+ size_t len;
+ void *ret;
+ char label[64];
+
+ printf ("-- memcpy --\n");
+
+ /* NULL */
+ _s_check_both_crash ("memcpy NULL dst", _s_ft_memcpy_null_dst,
+ _s_libc_memcpy_null_dst);
+ _s_check_both_crash ("memcpy NULL src", _s_ft_memcpy_null_src,
+ _s_libc_memcpy_null_src);
+
+ /* fill source with pattern */
+ for (i = 0; i < 256; i++)
+ src[i] = i;
+
+ /* zero length */
+ memset (ft_dst, 'X', 256);
+ memset (libc_dst, 'X', 256);
+ ft_memcpy (ft_dst, src, 0);
+ memcpy (libc_dst, src, 0);
+ _s_check ("n=0", memcmp (ft_dst, libc_dst, 256) == 0);
+
+ /* return value */
+ ret = ft_memcpy (ft_dst, src, 10);
+ _s_check ("return value", ret == ft_dst);
+
+ /* NULL src and dst with n=0 */
+ ret = ft_memcpy (NULL, NULL, 0);
+ _s_check ("NULL,NULL,0", ret == NULL);
+
+ /* randomized */
+ for (i = 0; i < 50; i++)
+ {
+ len = rand () % 256;
+ memset (ft_dst, 0, 256);
+ memset (libc_dst, 0, 256);
+ ft_memcpy (ft_dst, src, len);
+ memcpy (libc_dst, src, len);
+ snprintf (label, sizeof (label), "random len=%zu", len);
+ _s_check (label, memcmp (ft_dst, libc_dst, 256) == 0);
+ }
+}
+
+/* ======================================
+ * memmove
+ * ====================================== */
+
+static void
+_s_test_memmove (void)
+{
+ char ft_buf[256];
+ char libc_buf[256];
+ int i;
+ size_t len;
+ size_t offset;
+ void *ret;
+ char label[64];
+
+ printf ("-- memmove --\n");
+
+ /* NULL */
+ _s_check_both_crash ("memmove NULL dst", _s_ft_memmove_null_dst,
+ _s_libc_memmove_null_dst);
+ _s_check_both_crash ("memmove NULL src", _s_ft_memmove_null_src,
+ _s_libc_memmove_null_src);
+
+ /* return value */
+ memset (ft_buf, 'A', 256);
+ ret = ft_memmove (ft_buf, ft_buf + 10, 10);
+ _s_check ("return value", ret == ft_buf);
+
+ /* NULL src and dst with n=0 */
+ ret = ft_memmove (NULL, NULL, 0);
+ _s_check ("NULL,NULL,0", ret == NULL);
+
+ /* forward overlap: src before dest */
+ for (i = 0; i < 256; i++)
+ ft_buf[i] = libc_buf[i] = i;
+ ft_memmove (ft_buf + 10, ft_buf, 100);
+ memmove (libc_buf + 10, libc_buf, 100);
+ _s_check ("forward overlap", memcmp (ft_buf, libc_buf, 256) == 0);
+
+ /* backward overlap: dest before src */
+ for (i = 0; i < 256; i++)
+ ft_buf[i] = libc_buf[i] = i;
+ ft_memmove (ft_buf, ft_buf + 10, 100);
+ memmove (libc_buf, libc_buf + 10, 100);
+ _s_check ("backward overlap", memcmp (ft_buf, libc_buf, 256) == 0);
+
+ /* non-overlapping */
+ for (i = 0; i < 256; i++)
+ ft_buf[i] = libc_buf[i] = i;
+ ft_memmove (ft_buf + 128, ft_buf, 50);
+ memmove (libc_buf + 128, libc_buf, 50);
+ _s_check ("non-overlapping", memcmp (ft_buf, libc_buf, 256) == 0);
+
+ /* randomized overlapping copies */
+ for (i = 0; i < 50; i++)
+ {
+ for (int j = 0; j < 256; j++)
+ ft_buf[j] = libc_buf[j] = rand () % 256;
+ len = rand () % 128 + 1;
+ offset = rand () % 128;
+ ft_memmove (ft_buf + offset, ft_buf, len);
+ memmove (libc_buf + offset, libc_buf, len);
+ snprintf (label, sizeof (label), "random overlap len=%zu off=%zu", len,
+ offset);
+ _s_check (label, memcmp (ft_buf, libc_buf, 256) == 0);
+ }
+}
+
+int
+main (void)
+{
+ printf ("=== mem functions ===\n");
+ _s_test_memset ();
+ _s_test_bzero ();
+ _s_test_memcpy ();
+ _s_test_memmove ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/test_search.c b/tests/test_search.c
new file mode 100644
index 0000000..faaaccd
--- /dev/null
+++ b/tests/test_search.c
@@ -0,0 +1,285 @@
+#include "../libft.h"
+#include "test_utils.h"
+#include <bsd/string.h>
+
+static void
+_s_ft_strchr_null (void)
+{
+ _s_sink = (size_t)ft_strchr (NULL, 'a');
+}
+static void
+_s_libc_strchr_null (void)
+{
+ _s_sink = (size_t)strchr (NULL, 'a');
+}
+static void
+_s_ft_strrchr_null (void)
+{
+ _s_sink = (size_t)ft_strrchr (NULL, 'a');
+}
+static void
+_s_libc_strrchr_null (void)
+{
+ _s_sink = (size_t)strrchr (NULL, 'a');
+}
+static void
+_s_ft_strnstr_null_big (void)
+{
+ _s_sink = (size_t)ft_strnstr (NULL, "abc", 10);
+}
+static void
+_s_libc_strnstr_null_big (void)
+{
+ _s_sink = (size_t)strnstr (NULL, "abc", 10);
+}
+static void
+_s_ft_strnstr_null_little (void)
+{
+ _s_sink = (size_t)ft_strnstr ("abc", NULL, 10);
+}
+static void
+_s_libc_strnstr_null_little (void)
+{
+ _s_sink = (size_t)strnstr ("abc", NULL, 10);
+}
+
+/* ======================================
+ * strchr
+ * ====================================== */
+
+static void
+_s_test_strchr (void)
+{
+ char buf[] = "hello world";
+ int i;
+ char label[64];
+
+ printf ("-- strchr --\n");
+
+ /* NULL */
+ _s_check_both_crash ("strchr NULL", _s_ft_strchr_null, _s_libc_strchr_null);
+
+ /* find first occurrence */
+ _s_check ("find 'l'", ft_strchr (buf, 'l') == strchr (buf, 'l'));
+
+ /* find first char */
+ _s_check ("find 'h'", ft_strchr (buf, 'h') == strchr (buf, 'h'));
+
+ /* find last char */
+ _s_check ("find 'd'", ft_strchr (buf, 'd') == strchr (buf, 'd'));
+
+ /* not found */
+ _s_check ("not found 'z'", ft_strchr (buf, 'z') == strchr (buf, 'z'));
+
+ /* find null terminator */
+ _s_check ("find '\\0'", ft_strchr (buf, '\0') == strchr (buf, '\0'));
+
+ /* empty string */
+ _s_check ("empty + 'a'", ft_strchr ("", 'a') == strchr ("", 'a'));
+ _s_check ("empty + '\\0'", ft_strchr ("", '\0') == strchr ("", '\0'));
+
+ /* int truncation to char */
+ _s_check ("int truncation",
+ ft_strchr (buf, 'h' + 256) == strchr (buf, 'h' + 256));
+
+ /* all printable ASCII */
+ for (i = 32; i < 127; i++)
+ {
+ snprintf (label, sizeof (label), "char %d in buf", i);
+ _s_check (label, ft_strchr (buf, i) == strchr (buf, i));
+ }
+
+ /* randomized */
+ srand (time (NULL));
+ for (i = 0; i < 50; i++)
+ {
+ char rnd[128];
+ int len = rand () % 127 + 1;
+ int j;
+ int c;
+ for (j = 0; j < len; j++)
+ rnd[j] = 'A' + rand () % 52;
+ rnd[len] = '\0';
+ c = 'A' + rand () % 52;
+ snprintf (label, sizeof (label), "random len=%d c=%c", len, c);
+ _s_check (label, ft_strchr (rnd, c) == strchr (rnd, c));
+ }
+}
+
+/* ======================================
+ * strrchr
+ * ====================================== */
+
+static void
+_s_test_strrchr (void)
+{
+ char buf[] = "hello world";
+ int i;
+ char label[64];
+
+ printf ("-- strrchr --\n");
+
+ /* NULL */
+ _s_check_both_crash ("strrchr NULL", _s_ft_strrchr_null,
+ _s_libc_strrchr_null);
+
+ /* find last occurrence */
+ _s_check ("find 'l'", ft_strrchr (buf, 'l') == strrchr (buf, 'l'));
+
+ /* only one occurrence */
+ _s_check ("find 'w'", ft_strrchr (buf, 'w') == strrchr (buf, 'w'));
+
+ /* find first char */
+ _s_check ("find 'h'", ft_strrchr (buf, 'h') == strrchr (buf, 'h'));
+
+ /* find last char */
+ _s_check ("find 'd'", ft_strrchr (buf, 'd') == strrchr (buf, 'd'));
+
+ /* not found */
+ _s_check ("not found 'z'", ft_strrchr (buf, 'z') == strrchr (buf, 'z'));
+
+ /* find null terminator */
+ _s_check ("find '\\0'", ft_strrchr (buf, '\0') == strrchr (buf, '\0'));
+
+ /* empty string */
+ _s_check ("empty + 'a'", ft_strrchr ("", 'a') == strrchr ("", 'a'));
+ _s_check ("empty + '\\0'", ft_strrchr ("", '\0') == strrchr ("", '\0'));
+
+ /* int truncation to char */
+ _s_check ("int truncation",
+ ft_strrchr (buf, 'l' + 256) == strrchr (buf, 'l' + 256));
+
+ /* multiple occurrences */
+ _s_check ("'o' last",
+ ft_strrchr ("foo bar boo", 'o') == strrchr ("foo bar boo", 'o'));
+
+ /* all printable ASCII */
+ for (i = 32; i < 127; i++)
+ {
+ snprintf (label, sizeof (label), "char %d in buf", i);
+ _s_check (label, ft_strrchr (buf, i) == strrchr (buf, i));
+ }
+
+ /* randomized */
+ for (i = 0; i < 50; i++)
+ {
+ char rnd[128];
+ int len = rand () % 127 + 1;
+ int j;
+ int c;
+ for (j = 0; j < len; j++)
+ rnd[j] = 'A' + rand () % 52;
+ rnd[len] = '\0';
+ c = 'A' + rand () % 52;
+ snprintf (label, sizeof (label), "random len=%d c=%c", len, c);
+ _s_check (label, ft_strrchr (rnd, c) == strrchr (rnd, c));
+ }
+}
+
+/* ======================================
+ * strnstr
+ * ====================================== */
+
+static void
+_s_test_strnstr (void)
+{
+ char hay[] = "hello world, hello earth";
+
+ printf ("-- strnstr --\n");
+
+ /* NULL */
+ _s_check_both_crash ("strnstr NULL big", _s_ft_strnstr_null_big,
+ _s_libc_strnstr_null_big);
+ _s_check_both_crash ("strnstr NULL little", _s_ft_strnstr_null_little,
+ _s_libc_strnstr_null_little);
+
+ /* empty needle */
+ _s_check ("empty needle", ft_strnstr (hay, "", 24) == strnstr (hay, "", 24));
+
+ /* empty haystack */
+ _s_check ("empty haystack",
+ ft_strnstr ("", "abc", 0) == strnstr ("", "abc", 0));
+ _s_check ("both empty", ft_strnstr ("", "", 0) == strnstr ("", "", 0));
+
+ /* basic find */
+ _s_check ("find 'world'",
+ ft_strnstr (hay, "world", 24) == strnstr (hay, "world", 24));
+
+ /* find at start */
+ _s_check ("find 'hello'",
+ ft_strnstr (hay, "hello", 24) == strnstr (hay, "hello", 24));
+
+ /* find at end */
+ _s_check ("find 'earth'",
+ ft_strnstr (hay, "earth", 24) == strnstr (hay, "earth", 24));
+
+ /* not found */
+ _s_check ("not found 'xyz'",
+ ft_strnstr (hay, "xyz", 24) == strnstr (hay, "xyz", 24));
+
+ /* needle longer than len */
+ _s_check ("needle beyond len",
+ ft_strnstr (hay, "world", 8) == strnstr (hay, "world", 8));
+
+ /* len=0 */
+ _s_check ("len=0",
+ ft_strnstr (hay, "hello", 0) == strnstr (hay, "hello", 0));
+
+ /* exact match at boundary */
+ _s_check ("exact boundary",
+ ft_strnstr (hay, "world", 11) == strnstr (hay, "world", 11));
+
+ /* one short of match */
+ _s_check ("one short",
+ ft_strnstr (hay, "world", 10) == strnstr (hay, "world", 10));
+
+ /* single char needle */
+ _s_check ("single char 'w'",
+ ft_strnstr (hay, "w", 24) == strnstr (hay, "w", 24));
+
+ /* needle same as haystack */
+ _s_check ("needle == haystack",
+ ft_strnstr ("abc", "abc", 3) == strnstr ("abc", "abc", 3));
+
+ /* needle longer than haystack */
+ _s_check ("needle > haystack",
+ ft_strnstr ("ab", "abc", 3) == strnstr ("ab", "abc", 3));
+
+ /* partial match then fail */
+ _s_check ("partial match",
+ ft_strnstr ("aab", "ab", 3) == strnstr ("aab", "ab", 3));
+
+ /* randomized */
+ for (int i = 0; i < 50; i++)
+ {
+ char rbig[128];
+ char rlittle[16];
+ int blen = rand () % 100 + 20;
+ int llen = rand () % 10 + 1;
+ size_t n;
+ int j;
+ char label[64];
+ for (j = 0; j < blen; j++)
+ rbig[j] = 'A' + rand () % 4;
+ rbig[blen] = '\0';
+ for (j = 0; j < llen; j++)
+ rlittle[j] = 'A' + rand () % 4;
+ rlittle[llen] = '\0';
+ n = rand () % (blen + 10);
+ snprintf (label, sizeof (label), "random blen=%d llen=%d n=%zu", blen,
+ llen, n);
+ _s_check (label,
+ ft_strnstr (rbig, rlittle, n) == strnstr (rbig, rlittle, n));
+ }
+}
+
+int
+main (void)
+{
+ printf ("=== search functions ===\n");
+ _s_test_strchr ();
+ _s_test_strrchr ();
+ _s_test_strnstr ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/test_strl.c b/tests/test_strl.c
new file mode 100644
index 0000000..1ef29af
--- /dev/null
+++ b/tests/test_strl.c
@@ -0,0 +1,252 @@
+#include "../libft.h"
+#include "test_utils.h"
+#include <bsd/string.h>
+
+static void
+_s_ft_strlcpy_null_dst (void)
+{
+ _s_sink = ft_strlcpy (NULL, "abc", 10);
+}
+static void
+_s_libc_strlcpy_null_dst (void)
+{
+ _s_sink = strlcpy (NULL, "abc", 10);
+}
+static void
+_s_ft_strlcpy_null_src (void)
+{
+ char buf[10];
+ _s_sink = ft_strlcpy (buf, NULL, 10);
+}
+static void
+_s_libc_strlcpy_null_src (void)
+{
+ char buf[10];
+ _s_sink = strlcpy (buf, NULL, 10);
+}
+static void
+_s_ft_strlcat_null_dst (void)
+{
+ _s_sink = ft_strlcat (NULL, "abc", 10);
+}
+static void
+_s_libc_strlcat_null_dst (void)
+{
+ _s_sink = strlcat (NULL, "abc", 10);
+}
+static void
+_s_ft_strlcat_null_src (void)
+{
+ char buf[10] = "hi";
+ _s_sink = ft_strlcat (buf, NULL, 10);
+}
+static void
+_s_libc_strlcat_null_src (void)
+{
+ char buf[10] = "hi";
+ _s_sink = strlcat (buf, NULL, 10);
+}
+
+/* ======================================
+ * strlcpy
+ * ====================================== */
+
+static void
+_s_test_strlcpy (void)
+{
+ char ft_dst[64];
+ char libc_dst[64];
+ size_t ft_ret;
+ size_t libc_ret;
+ int i;
+ size_t size;
+ char src[64];
+ char label[64];
+
+ printf ("-- strlcpy --\n");
+
+ /* NULL */
+ _s_check_both_crash ("strlcpy NULL dst", _s_ft_strlcpy_null_dst,
+ _s_libc_strlcpy_null_dst);
+ _s_check_both_crash ("strlcpy NULL src", _s_ft_strlcpy_null_src,
+ _s_libc_strlcpy_null_src);
+
+ /* basic copy */
+ ft_ret = ft_strlcpy (ft_dst, "hello", 64);
+ libc_ret = strlcpy (libc_dst, "hello", 64);
+ _s_check ("basic copy ret", ft_ret == libc_ret);
+ _s_check ("basic copy buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* size=0 */
+ memset (ft_dst, 'X', 64);
+ memset (libc_dst, 'X', 64);
+ ft_ret = ft_strlcpy (ft_dst, "hello", 0);
+ libc_ret = strlcpy (libc_dst, "hello", 0);
+ _s_check ("size=0 ret", ft_ret == libc_ret);
+ _s_check ("size=0 buf unchanged", ft_dst[0] == 'X');
+
+ /* truncation */
+ ft_ret = ft_strlcpy (ft_dst, "hello world", 6);
+ libc_ret = strlcpy (libc_dst, "hello world", 6);
+ _s_check ("truncate ret", ft_ret == libc_ret);
+ _s_check ("truncate buf", strcmp (ft_dst, libc_dst) == 0);
+ _s_check ("truncate null term", ft_dst[5] == '\0');
+
+ /* exact fit */
+ ft_ret = ft_strlcpy (ft_dst, "abc", 4);
+ libc_ret = strlcpy (libc_dst, "abc", 4);
+ _s_check ("exact fit ret", ft_ret == libc_ret);
+ _s_check ("exact fit buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* empty src */
+ ft_ret = ft_strlcpy (ft_dst, "", 64);
+ libc_ret = strlcpy (libc_dst, "", 64);
+ _s_check ("empty src ret", ft_ret == libc_ret);
+ _s_check ("empty src buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* size=1 */
+ ft_ret = ft_strlcpy (ft_dst, "hello", 1);
+ libc_ret = strlcpy (libc_dst, "hello", 1);
+ _s_check ("size=1 ret", ft_ret == libc_ret);
+ _s_check ("size=1 buf", ft_dst[0] == '\0');
+
+ /* randomized */
+ srand (time (NULL));
+ for (i = 0; i < 50; i++)
+ {
+ int len = rand () % 60 + 1;
+ int j;
+ for (j = 0; j < len; j++)
+ src[j] = 'A' + rand () % 26;
+ src[len] = '\0';
+ size = rand () % 64;
+ memset (ft_dst, 'Z', 64);
+ memset (libc_dst, 'Z', 64);
+ ft_ret = ft_strlcpy (ft_dst, src, size);
+ libc_ret = strlcpy (libc_dst, src, size);
+ snprintf (label, sizeof (label), "random len=%d size=%zu", len, size);
+ _s_check (label,
+ ft_ret == libc_ret && memcmp (ft_dst, libc_dst, 64) == 0);
+ }
+}
+
+/* ======================================
+ * strlcat
+ * ====================================== */
+
+static void
+_s_test_strlcat (void)
+{
+ char ft_dst[64];
+ char libc_dst[64];
+ size_t ft_ret;
+ size_t libc_ret;
+ int i;
+ size_t size;
+ char label[64];
+
+ printf ("-- strlcat --\n");
+
+ /* NULL */
+ _s_check_both_crash ("strlcat NULL dst", _s_ft_strlcat_null_dst,
+ _s_libc_strlcat_null_dst);
+ _s_check_both_crash ("strlcat NULL src", _s_ft_strlcat_null_src,
+ _s_libc_strlcat_null_src);
+
+ /* basic concat */
+ strcpy (ft_dst, "hello");
+ strcpy (libc_dst, "hello");
+ ft_ret = ft_strlcat (ft_dst, " world", 64);
+ libc_ret = strlcat (libc_dst, " world", 64);
+ _s_check ("basic ret", ft_ret == libc_ret);
+ _s_check ("basic buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* size=0 */
+ strcpy (ft_dst, "hi");
+ strcpy (libc_dst, "hi");
+ ft_ret = ft_strlcat (ft_dst, "abc", 0);
+ libc_ret = strlcat (libc_dst, "abc", 0);
+ _s_check ("size=0 ret", ft_ret == libc_ret);
+
+ /* size == dstlen (no room to append) */
+ strcpy (ft_dst, "hello");
+ strcpy (libc_dst, "hello");
+ ft_ret = ft_strlcat (ft_dst, "abc", 5);
+ libc_ret = strlcat (libc_dst, "abc", 5);
+ _s_check ("size == dstlen ret", ft_ret == libc_ret);
+ _s_check ("size == dstlen buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* size less than dst len */
+ strcpy (ft_dst, "hello");
+ strcpy (libc_dst, "hello");
+ ft_ret = ft_strlcat (ft_dst, "abc", 3);
+ libc_ret = strlcat (libc_dst, "abc", 3);
+ _s_check ("size < dstlen ret", ft_ret == libc_ret);
+ _s_check ("size < dstlen buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* truncation */
+ strcpy (ft_dst, "hello");
+ strcpy (libc_dst, "hello");
+ ft_ret = ft_strlcat (ft_dst, " world", 8);
+ libc_ret = strlcat (libc_dst, " world", 8);
+ _s_check ("truncate ret", ft_ret == libc_ret);
+ _s_check ("truncate buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* exact fit */
+ strcpy (ft_dst, "abc");
+ strcpy (libc_dst, "abc");
+ ft_ret = ft_strlcat (ft_dst, "de", 6);
+ libc_ret = strlcat (libc_dst, "de", 6);
+ _s_check ("exact fit ret", ft_ret == libc_ret);
+ _s_check ("exact fit buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* empty src */
+ strcpy (ft_dst, "hello");
+ strcpy (libc_dst, "hello");
+ ft_ret = ft_strlcat (ft_dst, "", 64);
+ libc_ret = strlcat (libc_dst, "", 64);
+ _s_check ("empty src ret", ft_ret == libc_ret);
+ _s_check ("empty src buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* empty dst */
+ ft_dst[0] = '\0';
+ libc_dst[0] = '\0';
+ ft_ret = ft_strlcat (ft_dst, "hello", 64);
+ libc_ret = strlcat (libc_dst, "hello", 64);
+ _s_check ("empty dst ret", ft_ret == libc_ret);
+ _s_check ("empty dst buf", strcmp (ft_dst, libc_dst) == 0);
+
+ /* randomized */
+ for (i = 0; i < 50; i++)
+ {
+ int dlen = rand () % 30;
+ int slen = rand () % 30 + 1;
+ int j;
+ for (j = 0; j < dlen; j++)
+ ft_dst[j] = libc_dst[j] = 'A' + rand () % 26;
+ ft_dst[dlen] = libc_dst[dlen] = '\0';
+ char src[64];
+ for (j = 0; j < slen; j++)
+ src[j] = 'a' + rand () % 26;
+ src[slen] = '\0';
+ size = rand () % 64;
+ memset (ft_dst + dlen + 1, 'Z', 63 - dlen);
+ memset (libc_dst + dlen + 1, 'Z', 63 - dlen);
+ ft_ret = ft_strlcat (ft_dst, src, size);
+ libc_ret = strlcat (libc_dst, src, size);
+ snprintf (label, sizeof (label), "random dlen=%d slen=%d size=%zu", dlen,
+ slen, size);
+ _s_check (label,
+ ft_ret == libc_ret && memcmp (ft_dst, libc_dst, 64) == 0);
+ }
+}
+
+int
+main (void)
+{
+ printf ("=== strlcpy/strlcat ===\n");
+ _s_test_strlcpy ();
+ _s_test_strlcat ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}
diff --git a/tests/test_strlen.c b/tests/test_strlen.c
new file mode 100644
index 0000000..ef569ff
--- /dev/null
+++ b/tests/test_strlen.c
@@ -0,0 +1,109 @@
+#include "../libft.h"
+#include "test_utils.h"
+
+static void
+_s_call_ft_strlen_null (void)
+{
+ _s_sink = ft_strlen (NULL);
+}
+
+static void
+_s_call_strlen_null (void)
+{
+ _s_sink = strlen (NULL);
+}
+
+static void
+_s_test_empty (void)
+{
+ printf ("-- empty string --\n");
+ _s_check_eq ("ft_strlen", ft_strlen (""), 0);
+ _s_check_eq ("libc strlen", strlen (""), 0);
+}
+
+static void
+_s_test_null (void)
+{
+ int ft_crashed;
+ int libc_crashed;
+
+ printf ("-- NULL --\n");
+ ft_crashed = _s_crashes (_s_call_ft_strlen_null);
+ libc_crashed = _s_crashes (_s_call_strlen_null);
+ if (ft_crashed && libc_crashed)
+ {
+ printf (" PASS both crash on NULL\n");
+ _s_pass++;
+ }
+ else if (ft_crashed == libc_crashed)
+ {
+ printf (" PASS both behave the same on NULL (no crash)\n");
+ _s_pass++;
+ }
+ else
+ {
+ printf (" FAIL ft_crashed=%d libc_crashed=%d\n", ft_crashed,
+ libc_crashed);
+ _s_fail++;
+ }
+}
+
+static void
+_s_test_random (int n)
+{
+ int i;
+ int len;
+ char *buf;
+ char label[64];
+
+ printf ("-- %d randomized tests --\n", n);
+ for (i = 0; i < n; i++)
+ {
+ len = rand () % 10000;
+ buf = malloc (len + 1);
+ if (!buf)
+ {
+ printf (" FAIL malloc\n");
+ _s_fail++;
+ return;
+ }
+ memset (buf, 'A' + (i % 26), len);
+ buf[len] = '\0';
+ snprintf (label, sizeof (label), "random len=%d", len);
+ _s_check_eq (label, ft_strlen (buf), strlen (buf));
+ free (buf);
+ }
+}
+
+static void
+_s_test_large (void)
+{
+ size_t len;
+ char *buf;
+
+ printf ("-- large string (100 MB) --\n");
+ len = 100 * 1024 * 1024;
+ buf = malloc (len + 1);
+ if (!buf)
+ {
+ printf (" SKIP could not allocate %zu bytes\n", len);
+ return;
+ }
+ memset (buf, 'X', len);
+ buf[len] = '\0';
+ _s_check_eq ("100 MB string", ft_strlen (buf), len);
+ free (buf);
+}
+
+int
+main (void)
+{
+ srand (time (NULL));
+ printf ("=== ft_strlen ===\n");
+ _s_test_empty ();
+ _s_test_null ();
+ _s_test_random (100);
+ _s_test_large ();
+ _s_print_results ();
+ return (_s_fail != 0);
+}