#include "libft.h" #include "test_utils.h" #include /* ── helpers ─────────────────────────────────────────────────────── */ static void _s_del (void *content) { free (content); } static void _s_toupper_content (void *content) { char *s; s = content; while (*s) { *s = toupper ((unsigned char)*s); s++; } } static void * _s_dup_content (void *content) { return (strdup (content)); } /** Build a list of @p n nodes, each containing strdup'd decimal string. */ static t_list * _s_build_list (int n) { t_list *lst; char buf[32]; int i; lst = NULL; for (i = 0; i < n; i++) { snprintf (buf, sizeof (buf), "%d", i); ft_lstadd_back (&lst, ft_lstnew (strdup (buf))); } return (lst); } /* ── ft_lstnew ───────────────────────────────────────────────────── */ static void _s_test_lstnew (void) { _s_section ("ft_lstnew"); /* basic */ { char *s = strdup ("hello"); t_list *n = ft_lstnew (s); _s_check ("content set", n && n->content == s); _s_check ("next NULL", n && n->next == NULL); free (s); free (n); } /* NULL content is valid */ { t_list *n = ft_lstnew (NULL); _s_check ("NULL content ok", n && n->content == NULL); _s_check ("NULL content next", n && n->next == NULL); free (n); } } /* ── ft_lstadd_front ─────────────────────────────────────────────── */ static void _s_test_lstadd_front (void) { int i; _s_section ("ft_lstadd_front"); /* prepend to empty list */ { t_list *lst = NULL; t_list *n = ft_lstnew (strdup ("first")); ft_lstadd_front (&lst, n); _s_check ("empty→head", lst == n); _s_check ("empty→next NULL", lst->next == NULL); ft_lstclear (&lst, _s_del); } /* prepend to non-empty */ { t_list *lst = ft_lstnew (strdup ("second")); t_list *old = lst; t_list *n = ft_lstnew (strdup ("first")); ft_lstadd_front (&lst, n); _s_check ("new head", lst == n); _s_check ("old follows", lst->next == old); ft_lstclear (&lst, _s_del); } /* randomized: build by prepending, verify reverse order */ for (i = 0; i < _S_RAND_ITERS; i++) { int count = rand () % 20 + 2; t_list *lst = NULL; t_list *cur; int j; int ok; for (j = 0; j < count; j++) { char buf[32]; snprintf (buf, sizeof (buf), "%d", j); ft_lstadd_front (&lst, ft_lstnew (strdup (buf))); } /* first node should contain the highest index */ ok = 1; cur = lst; for (j = count - 1; j >= 0; j--) { char buf[32]; snprintf (buf, sizeof (buf), "%d", j); if (!cur || strcmp (cur->content, buf) != 0) { ok = 0; break; } cur = cur->next; } _s_check ("prepend order", ok); ft_lstclear (&lst, _s_del); } } /* ── ft_lstsize ──────────────────────────────────────────────────── */ static void _s_test_lstsize (void) { int i; char label[64]; _s_section ("ft_lstsize"); _s_check_eq_int ("NULL→0", ft_lstsize (NULL), 0); { t_list *lst = ft_lstnew (NULL); _s_check_eq_int ("single→1", ft_lstsize (lst), 1); free (lst); } /* randomized */ for (i = 0; i < _S_RAND_ITERS; i++) { int count = rand () % 100 + 1; t_list *lst = _s_build_list (count); snprintf (label, sizeof (label), "size=%d", count); _s_check_eq_int (label, ft_lstsize (lst), count); ft_lstclear (&lst, _s_del); } } /* ── ft_lstlast ──────────────────────────────────────────────────── */ static void _s_test_lstlast (void) { _s_section ("ft_lstlast"); _s_check ("NULL→NULL", ft_lstlast (NULL) == NULL); /* single node */ { t_list *lst = ft_lstnew (strdup ("only")); t_list *last = ft_lstlast (lst); _s_check ("single is last", last == lst); _s_check ("last->next NULL", last->next == NULL); ft_lstclear (&lst, _s_del); } /* multi node */ { t_list *lst = _s_build_list (5); t_list *last = ft_lstlast (lst); _s_check ("last content", last && strcmp (last->content, "4") == 0); _s_check ("last->next NULL", last && last->next == NULL); ft_lstclear (&lst, _s_del); } } /* ── ft_lstadd_back ──────────────────────────────────────────────── */ static void _s_test_lstadd_back (void) { int i; char label[64]; _s_section ("ft_lstadd_back"); /* append to empty list */ { t_list *lst = NULL; t_list *n = ft_lstnew (strdup ("first")); ft_lstadd_back (&lst, n); _s_check ("empty→head", lst == n); _s_check ("empty→next NULL", lst->next == NULL); ft_lstclear (&lst, _s_del); } /* append to non-empty */ { t_list *lst = ft_lstnew (strdup ("first")); t_list *n = ft_lstnew (strdup ("second")); ft_lstadd_back (&lst, n); _s_check ("head unchanged", strcmp (lst->content, "first") == 0); _s_check ("tail is new", lst->next == n); ft_lstclear (&lst, _s_del); } /* randomized: build by appending, verify order */ for (i = 0; i < _S_RAND_ITERS; i++) { int count = rand () % 20 + 2; t_list *lst = _s_build_list (count); t_list *cur; int j; int ok; ok = 1; cur = lst; for (j = 0; j < count; j++) { char buf[32]; snprintf (buf, sizeof (buf), "%d", j); if (!cur || strcmp (cur->content, buf) != 0) { ok = 0; break; } cur = cur->next; } snprintf (label, sizeof (label), "append order n=%d", count); _s_check (label, ok); ft_lstclear (&lst, _s_del); } } /* ── ft_lstdelone ────────────────────────────────────────────────── */ static void _s_test_lstdelone (void) { _s_section ("ft_lstdelone"); /* does not free next */ { t_list *a = ft_lstnew (strdup ("first")); t_list *b = ft_lstnew (strdup ("second")); a->next = b; ft_lstdelone (a, _s_del); /* b must still be accessible */ _s_check ("next survives", strcmp (b->content, "second") == 0); ft_lstdelone (b, _s_del); } /* single node */ { t_list *n = ft_lstnew (strdup ("only")); ft_lstdelone (n, _s_del); _s_check ("single delone ok", 1); } } /* ── ft_lstclear ─────────────────────────────────────────────────── */ static void _s_test_lstclear (void) { int i; char label[64]; _s_section ("ft_lstclear"); /* NULL list */ { t_list *lst = NULL; ft_lstclear (&lst, _s_del); _s_check ("NULL clear safe", lst == NULL); } /* single */ { t_list *lst = ft_lstnew (strdup ("only")); ft_lstclear (&lst, _s_del); _s_check ("single cleared", lst == NULL); } /* multi */ { t_list *lst = _s_build_list (5); ft_lstclear (&lst, _s_del); _s_check ("multi cleared", lst == NULL); } /* randomized */ for (i = 0; i < _S_RAND_ITERS; i++) { int count = rand () % 50 + 1; t_list *lst = _s_build_list (count); ft_lstclear (&lst, _s_del); snprintf (label, sizeof (label), "clear n=%d", count); _s_check (label, lst == NULL); } } /* ── ft_lstiter ──────────────────────────────────────────────────── */ static void _s_test_lstiter (void) { _s_section ("ft_lstiter"); /* NULL list does not crash */ ft_lstiter (NULL, _s_toupper_content); _s_check ("NULL safe", 1); /* apply toupper */ { t_list *lst = NULL; ft_lstadd_back (&lst, ft_lstnew (strdup ("hello"))); ft_lstadd_back (&lst, ft_lstnew (strdup ("world"))); ft_lstiter (lst, _s_toupper_content); _s_check ("iter[0]", strcmp (lst->content, "HELLO") == 0); _s_check ("iter[1]", strcmp (lst->next->content, "WORLD") == 0); ft_lstclear (&lst, _s_del); } /* randomized: build list, iter toupper, verify */ { int i; for (i = 0; i < _S_RAND_ITERS; i++) { int count = rand () % 20 + 1; t_list *lst = _s_build_list (count); t_list *cur; int ok; ft_lstiter (lst, _s_toupper_content); ok = 1; cur = lst; while (cur) { char *s = cur->content; while (*s) { if (*s >= 'a' && *s <= 'z') { ok = 0; break; } s++; } cur = cur->next; } _s_check ("iter toupper", ok); ft_lstclear (&lst, _s_del); } } } /* ── ft_lstmap ───────────────────────────────────────────────────── */ static void _s_test_lstmap (void) { int i; _s_section ("ft_lstmap"); /* NULL list */ { t_list *res = ft_lstmap (NULL, _s_dup_content, _s_del); _s_check ("NULL→NULL", res == NULL); } /* basic map (strdup) */ { t_list *lst = NULL; t_list *mapped; ft_lstadd_back (&lst, ft_lstnew (strdup ("hello"))); ft_lstadd_back (&lst, ft_lstnew (strdup ("world"))); mapped = ft_lstmap (lst, _s_dup_content, _s_del); _s_check ("map[0]", mapped && strcmp (mapped->content, "hello") == 0); _s_check ("map[1]", mapped && mapped->next && strcmp (mapped->next->content, "world") == 0); /* original unchanged */ _s_check ("orig[0]", strcmp (lst->content, "hello") == 0); /* independent nodes */ _s_check ("indep ptr", mapped->content != lst->content); ft_lstclear (&lst, _s_del); ft_lstclear (&mapped, _s_del); } /* randomized: build, map, verify same content but independent */ for (i = 0; i < _S_RAND_ITERS; i++) { int count = rand () % 20 + 1; t_list *lst = _s_build_list (count); t_list *mapped = ft_lstmap (lst, _s_dup_content, _s_del); t_list *a; t_list *b; int ok; ok = 1; a = lst; b = mapped; while (a && b) { if (strcmp (a->content, b->content) != 0 || a->content == b->content) { ok = 0; break; } a = a->next; b = b->next; } if (a || b) ok = 0; _s_check ("map rand", ok); ft_lstclear (&lst, _s_del); ft_lstclear (&mapped, _s_del); } } /* ── main ────────────────────────────────────────────────────────── */ int main (void) { srand (time (NULL)); _s_test_lstnew (); _s_test_lstadd_front (); _s_test_lstsize (); _s_test_lstlast (); _s_test_lstadd_back (); _s_test_lstdelone (); _s_test_lstclear (); _s_test_lstiter (); _s_test_lstmap (); _s_print_results (); return (_s_fail != 0); }