diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..144443e Binary files /dev/null and b/.DS_Store differ diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..ad18b71 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "macFrameworkPath": [ + "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" + ], + "compilerPath": "/opt/homebrew/bin/gcc", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "macos-clang-arm64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5c7247b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..f18deae --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,27 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: gcc kompiluj aktywny plik", + "command": "/opt/homebrew/bin/gcc", + "args": [ + "-Wall", "-Wextra", "-Wno-implicit-fallthrough", "-std=gnu17", "-fPIC", "-O2", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Zadanie wygenerowane przez debuger." + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/malloc.h b/malloc.h new file mode 100644 index 0000000..c91eed4 --- /dev/null +++ b/malloc.h @@ -0,0 +1,196 @@ +#ifndef _MALLOC_H +#define _MALLOC_H 1 + +#ifdef _LIBC +#include +#endif + +#if defined(__STDC__) || defined(__cplusplus) +#include +#define __malloc_ptr_t void * +#else +#undef size_t +#define size_t unsigned int +#undef ptrdiff_t +#define ptrdiff_t int +#define __malloc_ptr_t char * +#endif + +#ifdef _LIBC +/* Used by GNU libc internals. */ +#define __malloc_size_t size_t +#define __malloc_ptrdiff_t ptrdiff_t +#elif !defined __attribute_malloc__ +#define __attribute_malloc__ +#endif + +#ifdef __GNUC__ + +/* GCC can always grok prototypes. For C++ programs we add throw() + to help it optimize the function calls. But this works only with + gcc 2.8.x and egcs. */ +#if defined __cplusplus && (__GNUC__ >= 3 || __GNUC_MINOR__ >= 8) +#define __THROW throw() +#else +#define __THROW +#endif +#define __MALLOC_P(args) args __THROW +/* This macro will be used for functions which might take C++ callback + functions. */ +#define __MALLOC_PMT(args) args + +#else /* Not GCC. */ + +#define __THROW + +#if (defined __STDC__ && __STDC__) || defined __cplusplus + +#define __MALLOC_P(args) args +#define __MALLOC_PMT(args) args + +#else /* Not ANSI C or C++. */ + +#define __MALLOC_P(args) () /* No prototypes. */ +#define __MALLOC_PMT(args) () + +#endif /* ANSI C or C++. */ + +#endif /* GCC. */ + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((__malloc_ptr_t)0) +#endif +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Allocate SIZE bytes of memory. */ + extern __malloc_ptr_t malloc __MALLOC_P((size_t __size)) __attribute_malloc__; + + /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ + extern __malloc_ptr_t calloc __MALLOC_P((size_t __nmemb, size_t __size)) + __attribute_malloc__; + + /* Re-allocate the previously allocated block in __ptr, making the new + block SIZE bytes long. */ + extern __malloc_ptr_t realloc __MALLOC_P((__malloc_ptr_t __ptr, + size_t __size)) + __attribute_malloc__; + + /* Free a block allocated by `malloc', `realloc' or `calloc'. */ + extern void free __MALLOC_P((__malloc_ptr_t __ptr)); + + /* Free a block allocated by `calloc'. */ + extern void cfree __MALLOC_P((__malloc_ptr_t __ptr)); + + /* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ + extern __malloc_ptr_t memalign __MALLOC_P((size_t __alignment, size_t __size)); + + /* Allocate SIZE bytes on a page boundary. */ + extern __malloc_ptr_t valloc __MALLOC_P((size_t __size)) __attribute_malloc__; + + /* Equivalent to valloc(minimum-page-that-holds(n)), that is, round up + __size to nearest pagesize. */ + extern __malloc_ptr_t pvalloc __MALLOC_P((size_t __size)) + __attribute_malloc__; + + /* Underlying allocation function; successive calls should return + contiguous pieces of memory. */ + extern __malloc_ptr_t(*__morecore) __MALLOC_PMT((ptrdiff_t __size)); + + /* Default value of `__morecore'. */ + extern __malloc_ptr_t __default_morecore __MALLOC_P((ptrdiff_t __size)) + __attribute_malloc__; + + /* SVID2/XPG mallinfo structure */ + + struct mallinfo + { + int arena; /* non-mmapped space allocated from system */ + int ordblks; /* number of free chunks */ + int smblks; /* number of fastbin blocks */ + int hblks; /* number of mmapped regions */ + int hblkhd; /* space in mmapped regions */ + int usmblks; /* maximum total allocated space */ + int fsmblks; /* space available in freed fastbin blocks */ + int uordblks; /* total allocated space */ + int fordblks; /* total free space */ + int keepcost; /* top-most, releasable (via malloc_trim) space */ + }; + + /* Returns a copy of the updated current mallinfo. */ + extern struct mallinfo mallinfo __MALLOC_P((void)); + +/* SVID2/XPG mallopt options */ +#ifndef M_MXFAST +#define M_MXFAST 1 /* maximum request size for "fastbins" */ +#endif +#ifndef M_NLBLKS +#define M_NLBLKS 2 /* UNUSED in this malloc */ +#endif +#ifndef M_GRAIN +#define M_GRAIN 3 /* UNUSED in this malloc */ +#endif +#ifndef M_KEEP +#define M_KEEP 4 /* UNUSED in this malloc */ +#endif + +/* mallopt options that actually do something */ +#define M_TRIM_THRESHOLD -1 +#define M_TOP_PAD -2 +#define M_MMAP_THRESHOLD -3 +#define M_MMAP_MAX -4 +#define M_CHECK_ACTION -5 + + /* General SVID/XPG interface to tunable parameters. */ + extern int mallopt __MALLOC_P((int __param, int __val)); + + /* Release all but __pad bytes of freed top-most memory back to the + system. Return 1 if successful, else 0. */ + extern int malloc_trim __MALLOC_P((size_t __pad)); + + /* Report the number of usable allocated bytes associated with allocated + chunk __ptr. */ + extern size_t malloc_usable_size __MALLOC_P((__malloc_ptr_t __ptr)); + + /* Prints brief summary statistics on stderr. */ + extern void malloc_stats __MALLOC_P((void)); + + /* Record the state of all malloc variables in an opaque data structure. */ + extern __malloc_ptr_t malloc_get_state __MALLOC_P((void)); + + /* Restore the state of all malloc variables from data obtained with + malloc_get_state(). */ + extern int malloc_set_state __MALLOC_P((__malloc_ptr_t __ptr)); + + /* Called once when malloc is initialized; redefining this variable in + the application provides the preferred way to set up the hook + pointers. */ + extern void(*__malloc_initialize_hook) __MALLOC_PMT((void)); + /* Hooks for debugging and user-defined versions. */ + extern void(*__free_hook) __MALLOC_PMT((__malloc_ptr_t __ptr, + __const __malloc_ptr_t)); + extern __malloc_ptr_t(*__malloc_hook) __MALLOC_PMT((size_t __size, + __const __malloc_ptr_t)); + extern __malloc_ptr_t(*__realloc_hook) __MALLOC_PMT((__malloc_ptr_t __ptr, + size_t __size, + __const __malloc_ptr_t)); + extern __malloc_ptr_t(*__memalign_hook) __MALLOC_PMT((size_t __alignment, + size_t __size, + __const __malloc_ptr_t)); + extern void(*__after_morecore_hook) __MALLOC_PMT((void)); + + /* Activate a standard set of debugging hooks. */ + extern void __malloc_check_init __MALLOC_P((void)); + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + +#endif /* malloc.h */ \ No newline at end of file diff --git a/memory_tests b/memory_tests new file mode 100644 index 0000000..9c21ce0 Binary files /dev/null and b/memory_tests differ diff --git a/memory_tests.c b/memory_tests.c new file mode 100644 index 0000000..ee7b61e --- /dev/null +++ b/memory_tests.c @@ -0,0 +1,113 @@ +#include "memory_tests.h" +#include +#include "malloc.h" +#include +#include + +// Ten plik musi kompilowany z opcjami -std=gnu17 i -fPIC, +// a linkowany z opcjami -Wl,--wrap=malloc -Wl,--wrap=calloc -Wl,--wrap=realloc +// -Wl,--wrap=reallocarray -Wl,--wrap=free -Wl,--wrap=strdup -Wl,--wrap=strndup. + +// Przechwytujemy funkcje alokujące i zwalniające pamięć. +void *__real_malloc(size_t size) __attribute__((weak)); +void *__real_calloc(size_t nmemb, size_t size) __attribute__((weak)); +void *__real_realloc(void *ptr, size_t size) __attribute__((weak)); +void *__real_reallocarray(void *ptr, size_t nmemb, size_t size) __attribute__((weak)); +char *__real_strdup(const char *s) __attribute__((weak)); +char *__real_strndup(const char *s, size_t size) __attribute__((weak)); +void __real_free(void *ptr) __attribute__((weak)); + +// Trzymamy globalnie informacje o alokacjach i zwolnieniach pamięci. +static memory_test_data_t test_data; + +// To jest prosty akcesor potrzebny do testowania. +memory_test_data_t *get_memory_test_data(void) +{ + return &test_data; +} + +// To jest prosty akcesor potrzebny do testowania. +char const *get_magic_string(void) +{ + static char const *magic = "quite long magic string"; + return magic; +} + +// W zadanym momencie alokacja pamięci zawodzi. +static bool should_fail(void) +{ + return ++test_data.call_counter == test_data.fail_counter; +} + +// Realokacja musi się udać, jeśli nie zwiększamy rozmiaru alokowanej pamięci. +static bool can_fail(void const *old_ptr, size_t new_size) +{ + if (old_ptr == NULL) + return true; + else + return new_size > malloc_usable_size((void *)old_ptr); +} + +// Symulujemy brak pamięci. +#define UNRELIABLE_ALLOC(ptr, size, fun, name) \ + do \ + { \ + test_data.call_total++; \ + if (ptr != NULL && size == 0) \ + { \ + /* Takie wywołanie realloc jest równoważne wywołaniu free(ptr). */ \ + test_data.free_counter++; \ + return fun; \ + } \ + void *p = can_fail(ptr, size) && should_fail() ? NULL : (fun); \ + if (p) \ + { \ + test_data.alloc_counter += ptr != p; \ + test_data.free_counter += ptr != p && ptr != NULL; \ + } \ + else \ + { \ + errno = ENOMEM; \ + test_data.function_name = name; \ + } \ + return p; \ + } while (0) + +void *__wrap_malloc(size_t size) +{ + UNRELIABLE_ALLOC(NULL, size, __real_malloc(size), "malloc"); +} + +void *__wrap_calloc(size_t nmemb, size_t size) +{ + UNRELIABLE_ALLOC(NULL, nmemb * size, __real_calloc(nmemb, size), "calloc"); +} + +void *__wrap_realloc(void *ptr, size_t size) +{ + UNRELIABLE_ALLOC(ptr, size, __real_realloc(ptr, size), "realloc"); +} + +void *__wrap_reallocarray(void *ptr, size_t nmemb, size_t size) +{ + UNRELIABLE_ALLOC(ptr, nmemb * size, __real_reallocarray(ptr, nmemb, size), "reallocarray"); +} + +char *__wrap_strdup(const char *s) +{ + UNRELIABLE_ALLOC(NULL, 0, __real_strdup(s), "strdup"); +} + +char *__wrap_strndup(const char *s, size_t size) +{ + UNRELIABLE_ALLOC(NULL, 0, __real_strndup(s, size), "strndup"); +} + +// Zwalnianie pamięci zawsze się udaje. Odnotowujemy jedynie fakt zwolnienia. +void __wrap_free(void *ptr) +{ + test_data.call_total++; + __real_free(ptr); + if (ptr) + test_data.free_counter++; +} diff --git a/memory_tests.h b/memory_tests.h new file mode 100644 index 0000000..77b91ae --- /dev/null +++ b/memory_tests.h @@ -0,0 +1,21 @@ +#ifndef MEMORY_TESTS_H +#define MEMORY_TESTS_H + +// To jest struktura przechowująca informacje o operacjach na pamięci. +// Nie pozwalamy kompilatorowi optymalizować operacji na tych wartościach. +typedef struct { + volatile unsigned call_total; // licznik wszystkich wywołań funkcji + volatile unsigned call_counter; // licznik wywołań alokacji + volatile unsigned fail_counter; // numer błędnej alokacji + volatile unsigned alloc_counter; // liczba wykonanych alokacji + volatile unsigned free_counter; // liczba wykonanych zwolnień + volatile char *function_name; // nazwa nieudanej funkcji +} memory_test_data_t; + +// Zapewnia dostęp do wyżej zdefiniowanej struktury. +memory_test_data_t * get_memory_test_data(void); + +// Daje wskaźnik na unikalny napis. +char const * get_magic_string(void); + +#endif diff --git a/seq.h b/seq.h new file mode 100644 index 0000000..784c973 --- /dev/null +++ b/seq.h @@ -0,0 +1,15 @@ +#ifndef SEQ_H +#define SEQ_H + +typedef struct seq seq_t; + +seq_t * seq_new(void); +void seq_delete(seq_t *p); +int seq_add(seq_t *p, char const *s); +int seq_remove(seq_t *p, char const *s); +int seq_valid(seq_t *p, char const *s); +int seq_set_name(seq_t *p, char const *s, char const *n); +char const * seq_get_name(seq_t *p, char const *s); +int seq_equiv(seq_t *p, char const *s1, char const *s2); + +#endif diff --git a/seq_example.c b/seq_example.c new file mode 100644 index 0000000..5b72881 --- /dev/null +++ b/seq_example.c @@ -0,0 +1,289 @@ +#include "seq.h" +#include "memory_tests.h" +#include +#include +#include + +/** MAKRA SKRACAJĄCE IMPLEMENTACJĘ TESTÓW **/ + +// To są możliwe wyniki testu. +#define PASS 0 +#define FAIL 1 +#define WRONG_TEST 2 + +// Oblicza liczbę elementów tablicy x. +#define SIZE(x) (sizeof x / sizeof x[0]) + +#define TEST_EINVAL(f) \ + do { \ + if ((f) != -1 || errno != EINVAL) \ + return FAIL; \ + } while (0) + +#define TEST_NULL_EINVAL(f) \ + do { \ + if ((f) != NULL || errno != EINVAL) \ + return FAIL; \ + } while (0) + +#define TEST_PASS(f) \ + do { \ + if ((f) != 1) \ + return FAIL; \ + } while (0) + +#define TEST_FAIL(f) \ + do { \ + if ((f) != 0) \ + return FAIL; \ + } while (0) + +#define TEST_COMP(f, s) \ + do { \ + if (strcmp((f), (s)) != 0) \ + return FAIL; \ + } while (0) + +#define TEST_NULL_FAIL(f) \ + do { \ + if ((f) != NULL || errno != 0) \ + return FAIL; \ + } while (0) + +#define V(code, where) (((unsigned long)code) << (3 * where)) + +/** WŁAŚCIWE TESTY **/ + +// Testuje poprawność weryfikacji parametrów wywołań funkcji. +static int params(void) { + static const char bad_seq[4] = {0, 1, 2, 3}; + + seq_t *seq = seq_new(); + + TEST_EINVAL(seq_add(NULL, "1")); + TEST_EINVAL(seq_add(seq, NULL)); + TEST_EINVAL(seq_add(seq, "")); + TEST_EINVAL(seq_add(seq, "/")); + TEST_EINVAL(seq_add(seq, "3")); + TEST_EINVAL(seq_add(seq, "10/")); + TEST_EINVAL(seq_add(seq, "103")); + TEST_EINVAL(seq_add(seq, bad_seq)); + + TEST_EINVAL(seq_remove(NULL, "2")); + TEST_EINVAL(seq_remove(seq, NULL)); + TEST_EINVAL(seq_remove(seq, "")); + TEST_EINVAL(seq_remove(seq, "/")); + TEST_EINVAL(seq_remove(seq, "3")); + TEST_EINVAL(seq_remove(seq, "21/")); + TEST_EINVAL(seq_remove(seq, "213")); + TEST_EINVAL(seq_remove(seq, bad_seq)); + + TEST_EINVAL(seq_valid(NULL, "0")); + TEST_EINVAL(seq_valid(seq, NULL)); + TEST_EINVAL(seq_valid(seq, "")); + TEST_EINVAL(seq_valid(seq, "/")); + TEST_EINVAL(seq_valid(seq, "3")); + TEST_EINVAL(seq_valid(seq, "0/0")); + TEST_EINVAL(seq_valid(seq, "030")); + TEST_EINVAL(seq_valid(seq, bad_seq)); + + TEST_EINVAL(seq_set_name(NULL, "0", "a")); + TEST_EINVAL(seq_set_name(seq, NULL, "b")); + TEST_EINVAL(seq_set_name(seq, "", "c")); + TEST_EINVAL(seq_set_name(seq, "1", NULL)); + TEST_EINVAL(seq_set_name(seq, "2", "")); + TEST_EINVAL(seq_set_name(seq, "/", "d")); + TEST_EINVAL(seq_set_name(seq, "3", "e")); + TEST_EINVAL(seq_set_name(seq, bad_seq, "f")); + + TEST_NULL_EINVAL(seq_get_name(NULL, "0")); + TEST_NULL_EINVAL(seq_get_name(seq, NULL)); + TEST_NULL_EINVAL(seq_get_name(seq, "")); + TEST_NULL_EINVAL(seq_get_name(seq, "/")); + TEST_NULL_EINVAL(seq_get_name(seq, "3")); + TEST_NULL_EINVAL(seq_get_name(seq, bad_seq)); + + TEST_EINVAL(seq_equiv(NULL, "0", "1")); + TEST_EINVAL(seq_equiv(seq, NULL, "1")); + TEST_EINVAL(seq_equiv(seq, "", "1")); + TEST_EINVAL(seq_equiv(seq, "0", NULL)); + TEST_EINVAL(seq_equiv(seq, "0", "")); + TEST_EINVAL(seq_equiv(seq, "/", "1")); + TEST_EINVAL(seq_equiv(seq, "3", "1")); + TEST_EINVAL(seq_equiv(seq, "0", "/")); + TEST_EINVAL(seq_equiv(seq, "0", "3")); + TEST_EINVAL(seq_equiv(seq, "0", bad_seq)); + TEST_EINVAL(seq_equiv(seq, bad_seq, "1")); + + seq_delete(seq); + return PASS; +} + +// Testuje podstawową funkcjonalność biblioteki. +static int simple(void) { + seq_t *seq = seq_new(); + + TEST_PASS(seq_add(seq, "012")); + TEST_FAIL(seq_add(seq, "01")); + TEST_FAIL(seq_remove(seq, "0120")); + + TEST_PASS(seq_valid(seq, "0")); + TEST_PASS(seq_valid(seq, "01")); + TEST_PASS(seq_valid(seq, "012")); + TEST_FAIL(seq_valid(seq, "0120")); + + TEST_PASS(seq_remove(seq, "01")); + + TEST_PASS(seq_valid(seq, "0")); + TEST_FAIL(seq_valid(seq, "01")); + TEST_FAIL(seq_valid(seq, "012")); + + seq_delete(seq); + return PASS; +} + +// Testuje tworzenie klas abstrakcji i przypisywanie im nazw. +static int equivalence(void) { + seq_t *seq = seq_new(); + + TEST_FAIL(seq_equiv(seq, "0", "1")); + + TEST_PASS(seq_add(seq, "00")); + TEST_FAIL(seq_equiv(seq, "00", "00")); + TEST_FAIL(seq_equiv(seq, "00", "11")); + + TEST_PASS(seq_set_name(seq, "0", "zero")); + TEST_COMP(seq_get_name(seq, "0"), "zero"); + TEST_FAIL(seq_set_name(seq, "0", "zero")); + TEST_PASS(seq_set_name(seq, "0", "ZERO")); + TEST_COMP(seq_get_name(seq, "0"), "ZERO"); + TEST_FAIL(seq_set_name(seq, "000", "trzy zera")); + TEST_NULL_FAIL(seq_get_name(seq, "00")); + TEST_NULL_FAIL(seq_get_name(seq, "1")); + + TEST_PASS(seq_add(seq, "11")); + + TEST_NULL_FAIL(seq_get_name(seq, "1")); + TEST_NULL_FAIL(seq_get_name(seq, "11")); + + TEST_PASS(seq_equiv(seq, "0", "1")); + TEST_FAIL(seq_equiv(seq, "0", "1")); + + TEST_COMP(seq_get_name(seq, "0"), "ZERO"); + TEST_COMP(seq_get_name(seq, "1"), "ZERO"); + + TEST_PASS(seq_equiv(seq, "00", "11")); + + TEST_PASS(seq_set_name(seq, "1", "JEDEN")); + TEST_COMP(seq_get_name(seq, "0"), "JEDEN"); + TEST_COMP(seq_get_name(seq, "1"), "JEDEN"); + TEST_PASS(seq_set_name(seq, "11", "DWA")); + TEST_COMP(seq_get_name(seq, "00"), "DWA"); + TEST_COMP(seq_get_name(seq, "11"), "DWA"); + + TEST_PASS(seq_equiv(seq, "11", "0")); + TEST_COMP(seq_get_name(seq, "0"), "DWAJEDEN"); + TEST_COMP(seq_get_name(seq, "1"), "DWAJEDEN"); + TEST_COMP(seq_get_name(seq, "00"), "DWAJEDEN"); + TEST_COMP(seq_get_name(seq, "11"), "DWAJEDEN"); + + TEST_FAIL(seq_equiv(seq, "11", "11")); + + seq_delete(seq); + return PASS; +} + +// Testuje reakcję implementacji na niepowodzenie alokacji pamięci. +static unsigned long alloc_fail_seq_new_seq_add(void) { + unsigned long visited = 0; + seq_t *seq; + int result; + + if ((seq = seq_new()) != NULL) + visited |= V(1, 0); + else if (errno == ENOMEM && (seq = seq_new()) != NULL) + visited |= V(2, 0); + else + return visited |= V(4, 0); + + if ((result = seq_add(seq, "012")) == 1) + visited |= V(1, 1); + else if (result == -1 && errno == ENOMEM && seq_valid(seq, "0") == 0 && + seq_valid(seq, "01") == 0 && seq_valid(seq, "012") == 0 && + seq_add(seq, "012") == 1) + visited |= V(2, 1); + else + return visited |= V(4, 1); + + seq_delete(seq); + + return visited; +} + +// Sprawdza reakcję implementacji na niepowodzenie alokacji pamięci. +static int memory_test(unsigned long (* test_function)(void)) { + memory_test_data_t *mtd = get_memory_test_data(); + + unsigned fail = 0, pass = 0; + mtd->call_total = 0; + mtd->fail_counter = 1; + while (fail < 3 && pass < 3) { + mtd->call_counter = 0; + mtd->alloc_counter = 0; + mtd->free_counter = 0; + mtd->function_name = NULL; + unsigned long visited_points = test_function(); + if (mtd->alloc_counter != mtd->free_counter || + (visited_points & 0444444444444444444444UL) != 0) { + fprintf(stderr, + "fail_counter %u, alloc_counter %u, free_counter %u, " + "function_name %s, visited_point %lo\n", + mtd->fail_counter, mtd->alloc_counter, mtd->free_counter, + mtd->function_name, visited_points); + ++fail; + } + if (mtd->function_name == NULL) + ++pass; + else + pass = 0; + mtd->fail_counter++; + } + + return mtd->call_total > 0 && fail == 0 ? PASS : FAIL; +} + +static int memory(void) { + return memory_test(alloc_fail_seq_new_seq_add); +} + +/** URUCHAMIANIE TESTÓW **/ + +typedef struct { + char const *name; + int (*function)(void); +} test_list_t; + +#define TEST(t) {#t, t} + +static const test_list_t test_list[] = { + TEST(params), + TEST(simple), + TEST(equivalence), + TEST(memory), +}; + +static int do_test(int (*function)(void)) { + int result = function(); + puts(get_magic_string()); + return result; +} + +int main(int argc, char *argv[]) { + if (argc == 2) + for (size_t i = 0; i < SIZE(test_list); ++i) + if (strcmp(argv[1], test_list[i].name) == 0) + return do_test(test_list[i].function); + + fprintf(stderr, "Użycie:\n%s nazwa_testu\n", argv[0]); + return WRONG_TEST; +}