#include <my_assert.h>


void __dfwmalloc_print_vitals (void);
int __dfwmalloc_get_bucket (struct dfwmalloc *dfw, LONG n);


STATICFN void dfwmalloc_test (void)
{
    int k;

    printf("\n");

    for (k = 0; k < 128 * 1024 * 1024; k++) {
        assert (__dfwmalloc_get_bucket (NULL, k) <= __dfwmalloc_get_bucket (NULL, k + 1));
        assert (__dfwmalloc_get_bucket (NULL, k + 1) <= __dfwmalloc_get_bucket (NULL, k) + 1);
    }
}

extern const char *dfwmalloc_version_str;

void dfwmalloc_test2 (void)
{
    char *p;
    long i, j, big, m;
    long last_i;
    char vers[64];

    assert ((dfwmalloc_version () >> 20) == DFWMALLOC_VERSION_MAJOR);
    assert (((dfwmalloc_version () >> 10) & 0x3FF) == DFWMALLOC_VERSION_MINOR);
    assert ((dfwmalloc_version () & 0x3FF) == DFWMALLOC_VERSION_PATCH);
    snprintf (vers, sizeof (vers), "DFWMALLOC VERSION %d.%d.%d", DFWMALLOC_VERSION_MAJOR, DFWMALLOC_VERSION_MINOR, DFWMALLOC_VERSION_PATCH);
    assert (!strcmp (vers, dfwmalloc_version_str));

    p = (char *) malloc (0);
    free (p);

    p = (char *) malloc (1);
    free (p);

    p = (char *) malloc (1);
    free (p);

    p = (char *) malloc (1);
    p = (char *) realloc (p, 1);
    p = (char *) realloc (p, 1);

    free (p);

    p = (char *) calloc (100, 1);
    assert (p != NULL);
    free (p);

    {
/* avoid gcc trying to be smart by using some trickery: */
        volatile long t[2];
        volatile long big2;
        big2 = 1L<<40;
        memcpy ((void *) &t[0], (void *) &big2, sizeof (long));
        memcpy ((void *) &t[1], (void *) &big2, sizeof (long));
        p = (char *) calloc (t[0], t[1]);
    }
    assert (p == NULL);
    assert (errno == ENOMEM);

    printf ("\n");

    p = (char *) malloc(100);
    p[0] = 'A';
    p[1] = 'B';
    p = (char *) realloc (p, 2);
    assert (p[0] == 'A');
    assert (p[1] == 'B');

    last_i = 2;
    big = 1 * 1024 * 1024;
    for (j = 'B', i = 3; i <= big; i = (i + 1) * 9 / 8, j++) {
        p[0] = (char) j;
        p[last_i - 1] = (char) (j + 1);
        p = (char *) realloc (p, i);
        assert (p != NULL);
        assert ((unsigned char) p[0] == (unsigned char) (j & 0xFF));
        assert ((unsigned char) p[last_i - 1] == (unsigned char) ((j + 1) & 0xFF));
        fflush (stdout);
        last_i = i;
    }
#if !defined(NULL_MODE) && defined(WITH_BTANDCHECK) && defined(WITH_ACCOUNTS)
//     printf("1. total: %ld\n", dfw->total_alloced_bt);
#endif

    last_i = 2;
    for (j = 'B', i = 3; i <= big; i = (i + 1) * 9 / 8, j++) {
        p[0] = (char) j;
        p[last_i - 1] = (char) (j + 1);
        p = (char *) realloc (p, i);
        assert ((unsigned char) p[0] == (unsigned char) (j & 0xFF));
        assert ((unsigned char) p[last_i - 1] == (unsigned char) ((j + 1) & 0xFF));
        fflush (stdout);
        last_i = i;
    }

    for (j = 'B', i = big / 2; i >= 4; i = (i * 7 / 8 - 1), j++) {
        p[0] = (char) j;
        p[i - 1] = (char) (j + 1);
        p = (char *) realloc (p, i);
        assert ((unsigned char) p[0] == (unsigned char) (j & 0xFF));
        assert ((unsigned char) p[i - 1] == (unsigned char) ((j + 1) & 0xFF));
        fflush (stdout);
    }
    free (p);
#if !defined(NULL_MODE) && defined(WITH_BTANDCHECK) && defined(WITH_ACCOUNTS)
//     printf("2. total: %ld\n", dfw->total_alloced_bt);
#endif

#ifdef FOR_VALGRIND
    m = 100;
#else
    m = 1000;
#endif
    for (i = 1; i < m; i++) {
        p = (char *) malloc(i);
        assert (p);
        memset(p, 255, i);
        free (p);
    }

#if !defined(NULL_MODE) && defined(WITH_BTANDCHECK) && defined(WITH_ACCOUNTS)
//     printf("3. total: %ld\n", dfw->total_alloced_bt);
#endif

    for (i = 1; i < m; i++) {
        p = (char *) malloc(i);
        memset(p, 255, i);
        free (p);
    }

    {
        char *q[1001];
        int n;
#if !defined(FEATHERWEIGHT) && !defined(FOR_VALGRIND)
        n = 1000;
#else
        n = 100;
#endif
        for (i = 1; i < n; i++) {
            q[i] = (char *) malloc (25);
            assert (q[i] != NULL);
            memset (q[i], 255, 25);
        }

        for (i = 1; i < n; i++) {
            free (q[i]);
        }
    }

#if !defined(NULL_MODE) && defined(WITH_BTANDCHECK) && defined(WITH_ACCOUNTS)
//     printf("4. total: %ld\n", dfw->total_alloced_bt);
#endif

#if !defined(NULL_MODE) && defined(WITH_ACCOUNTS)
//     for (i = 1; i < global->n_freelists; i++) {
//         if (dfw->free_list[i].count > 1) {
//             printf("free list %ld: %d\n", i, dfw->free_list[i].count);
//         }
//     }
#endif

#if !defined(NULL_MODE) && defined(WITH_BTANDCHECK) && defined(WITH_ACCOUNTS)
//     printf("5. total: %ld\n", dfw->total_alloced_bt);
#endif
}


void entry (void)
{
    printf ("basic tests\n");
    __dfwmalloc_print_vitals ();
    dfwmalloc_test ();
    dfwmalloc_test2 ();
}

