/* ---------------------------------------------------------------------
   (c) ED 2005
   Project      : CLIB
   Function     : Generic Linked list (Unit test)
   Module       : GLL
   File         : tgll.c
   Created      : 26-08-2005
   Modified     : 28-08-2005
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Log

   1.0 28-08-2005 Intial version
   0.0 26-08-2005 Created

   --------------------------------------------------------------------- */
#ifdef __cplusplus
#error This is not C++. Please use a C compiler.
#endif

#include "ed/inc/gll.h"
#include "ed/inc/sysalloc.h"
#include "ed/inc/sys.h"

/* private macro definitions =========================================== */
#define DBG 0

#define ID "TGLL"
#define VER "1.0"

#if DBG
#define MODULE ID"."
#else
#endif

#define PERR(err)                 \
do                                \
{                                 \
   if (err != GLL_OK)             \
   {                              \
      printf ("err = %s(%u)\n"    \
              , gll_serr(err)     \
              , (uint) err);      \
   }                              \
}                                 \
while (0)

#define TEST(n) \
   puts("test_" #n), test_ ## n(), puts ("P A S S E D\n")

#define PRT(s) \
   printf(#s"='%s'\n", s)

/* private constants =================================================== */

/* private types ======================================================= */

/* private structures ================================================== */

typedef struct
{
   int data;
}
user_s;

/* private functions =================================================== */

/* ---------------------------------------------------------------------
   test_1 ()
   ---------------------------------------------------------------------
   tests on an empty list
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void test_1 (void)
{
   gll_s *p_obj = gll_create ();

   if (p_obj != NULL)
   {
      gll_err_e err;

      ASSERT (gll_is_empty (p_obj, &err) == 1);
      ASSERT (err == GLL_OK);

      err = gll_goto_head (p_obj);
      ASSERT (err == GLL_ERR_EMPTY);

      err = gll_goto_tail (p_obj);
      ASSERT (err == GLL_ERR_EMPTY);

      err = gll_next (p_obj);
      ASSERT (err == GLL_ERR_EMPTY);

      err = gll_prev (p_obj);
      ASSERT (err == GLL_ERR_EMPTY);

      {
         void const *p_data = gll_read_data (p_obj, &err);
         ASSERT (err == GLL_ERR_EMPTY);
         ASSERT (p_data == NULL);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_ERR_EMPTY);
         ASSERT (p_data == NULL);
      }

      err = gll_clear (p_obj);
      ASSERT (err == GLL_OK);

      gll_delete (p_obj), p_obj = NULL;
   }
   ASSERT (p_obj == NULL);
}

/* ---------------------------------------------------------------------
   test_2 ()
   ---------------------------------------------------------------------
   tests with one node
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void test_2 (void)
{
   gll_s *p_obj = gll_create ();

   if (p_obj != NULL)
   {
      gll_err_e err;

      err = gll_insert_left (p_obj, "Hello");
      ASSERT (err == GLL_OK);

      /* --------------------------------------------
         current is now initialized
         -------------------------------------------- */

      ASSERT (gll_is_empty (p_obj, &err) == 0);
      ASSERT (err == GLL_OK);

      err = gll_prev (p_obj);
      ASSERT (err == GLL_ERR_CURR_AT_TOP);

      err = gll_next (p_obj);
      ASSERT (err == GLL_ERR_CURR_AT_END);

      {
         void const *p_data = gll_read_data (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (strcmp (p_data, "Hello") == 0);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (p_data != NULL);
         ASSERT (strcmp (p_data, "Hello") == 0);
      }

      /* --------------------------------------------
         current is not yet initialized
         -------------------------------------------- */

      err = gll_goto_head (p_obj);
      ASSERT (err == GLL_ERR_EMPTY);

      err = gll_prev (p_obj);
      ASSERT (err == GLL_ERR_EMPTY);

      err = gll_next (p_obj);
      ASSERT (err == GLL_ERR_EMPTY);

      err = gll_goto_tail (p_obj);
      ASSERT (err == GLL_ERR_EMPTY);

      {
         void const *p_data = gll_read_data (p_obj, &err);
         ASSERT (err == GLL_ERR_EMPTY);
         ASSERT (p_data == NULL);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_ERR_EMPTY);
         ASSERT (p_data == NULL);
      }

      ASSERT (gll_is_empty (p_obj, &err) == 1);
      ASSERT (err == GLL_OK);

      err = gll_insert_right (p_obj, "world");
      ASSERT (err == GLL_OK);

      /* --------------------------------------------
         current is now initialized
         -------------------------------------------- */

      {
         void const *p_data = gll_read_data (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (p_data != NULL);
         ASSERT (strcmp (p_data, "world") == 0);
      }

      err = gll_clear (p_obj);
      ASSERT (err == GLL_OK);

      /* --------------------------------------------
         current is not yet initialized
         -------------------------------------------- */

      ASSERT (gll_is_empty (p_obj, &err) == 1);
      ASSERT (err == GLL_OK);

      gll_delete (p_obj), p_obj = NULL;
   }
   ASSERT (p_obj == NULL);
}

/* ---------------------------------------------------------------------
   test_3 ()
   ---------------------------------------------------------------------
   tests with two nodes
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void test_3 (void)
{
   gll_s *p_obj = gll_create ();

   if (p_obj != NULL)
   {
      gll_err_e err;

      err = gll_insert_left (p_obj, "world");
      ASSERT (err == GLL_OK);

      /* --------------------------------------------
         current is now initialized
         -------------------------------------------- */

      err = gll_insert_left (p_obj, "Hello");
      ASSERT (err == GLL_OK);

      ASSERT (gll_is_empty (p_obj, &err) == 0);
      ASSERT (err == GLL_OK);

      err = gll_prev (p_obj);
      ASSERT (err == GLL_ERR_CURR_AT_TOP);

      err = gll_next (p_obj);
      ASSERT (err == GLL_OK);

      err = gll_next (p_obj);
      ASSERT (err == GLL_ERR_CURR_AT_END);

      {
         char s[128] = "";

         do
         {
            void const *p_data = gll_read_data (p_obj, &err);

            ASSERT (p_data != NULL);
            ASSERT (err == GLL_OK);

            strcat (s, p_data);

            err = gll_next (p_obj);

         }
         while (err == GLL_OK);

         ASSERT (strcmp (s, "world") == 0);
      }

      err = gll_goto_head (p_obj);
      ASSERT (err == GLL_OK);

      {
         char s[128] = "";

         do
         {
            void const *p_data = gll_read_data (p_obj, &err);

            ASSERT (p_data != NULL);
            ASSERT (err == GLL_OK);

            strcat (s, p_data);

            err = gll_next (p_obj);

         }
         while (err == GLL_OK);

         ASSERT (strcmp (s, "Helloworld") == 0);
      }

      {
         void const *p_data = gll_read_data (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (p_data != NULL);
         ASSERT (strcmp (p_data, "world") == 0);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (p_data != NULL);
         ASSERT (strcmp (p_data, "world") == 0);
      }


      err = gll_goto_tail (p_obj);
      ASSERT (err == GLL_OK);

      err = gll_prev (p_obj);
      ASSERT (err == GLL_ERR_CURR_AT_TOP);

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (p_data != NULL);
         ASSERT (strcmp (p_data, "Hello") == 0);
      }

      ASSERT (gll_is_empty (p_obj, &err) == 1);
      ASSERT (err == GLL_OK);

      /* --------------------------------------------
         current is not yet initialized
         -------------------------------------------- */

      err = gll_insert_right (p_obj, "Hello");
      ASSERT (err == GLL_OK);

      /* --------------------------------------------
         current is now initialized
         -------------------------------------------- */

      err = gll_insert_right (p_obj, "world");
      ASSERT (err == GLL_OK);

      ASSERT (gll_is_empty (p_obj, &err) == 0);
      ASSERT (err == GLL_OK);

      err = gll_goto_head (p_obj);
      ASSERT (err == GLL_OK);

      {
         char s[128] = "";

         do
         {
            void const *p_data = gll_read_data (p_obj, &err);

            ASSERT (p_data != NULL);
            ASSERT (err == GLL_OK);

            strcat (s, p_data);

            err = gll_next (p_obj);

         }
         while (err == GLL_OK);

         ASSERT (strcmp (s, "Helloworld") == 0);
      }

      err = gll_goto_head (p_obj);
      ASSERT (err == GLL_OK);

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (p_data != NULL);
         ASSERT (strcmp (p_data, "Hello") == 0);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (p_data != NULL);
         ASSERT (strcmp (p_data, "world") == 0);
      }

      /* --------------------------------------------
         current is not yet initialized
         -------------------------------------------- */

      ASSERT (gll_is_empty (p_obj, &err) == 1);
      ASSERT (err == GLL_OK);

      gll_delete (p_obj), p_obj = NULL;
      PERR (err);
   }
   ASSERT (p_obj == NULL);
}

/* ---------------------------------------------------------------------
   test_4 ()
   ---------------------------------------------------------------------
   tests with three nodes
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void test_4 (void)
{
   gll_s *p_obj = gll_create ();

   if (p_obj != NULL)
   {
      gll_err_e err;

      err = gll_insert_left (p_obj, "world");
      ASSERT (err == GLL_OK);

      err = gll_insert_left (p_obj, "wild");
      ASSERT (err == GLL_OK);

      err = gll_insert_left (p_obj, "Hello");
      ASSERT (err == GLL_OK);

      ASSERT (gll_is_empty (p_obj, &err) == 0);
      ASSERT (err == GLL_OK);

      {
         void const *p_data = gll_read_data (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (p_data != NULL);
         ASSERT (strcmp (p_data, "Hello") == 0);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (p_data != NULL);
         ASSERT (strcmp (p_data, "Hello") == 0);
      }


      err = gll_goto_tail (p_obj);
      ASSERT (err == GLL_OK);

      /* --------------------------------------------
         current is now initialized
         -------------------------------------------- */

      err = gll_prev (p_obj);
      ASSERT (err == GLL_OK);

      err = gll_prev (p_obj);
      ASSERT (err == GLL_ERR_CURR_AT_TOP);

      {
         char s[128] = "";

         do
         {
            void const *p_data = gll_read_data (p_obj, &err);

            ASSERT (p_data != NULL);
            ASSERT (err == GLL_OK);

            strcat (s, p_data);

            err = gll_next (p_obj);

         }
         while (err == GLL_OK);

         ASSERT (strcmp (s, "wildworld") == 0);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (strcmp (p_data, "world") == 0);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (strcmp (p_data, "wild") == 0);
      }

      /* --------------------------------------------
         current is not yet initialized
         -------------------------------------------- */

      err = gll_insert_right (p_obj, "Hello");
      ASSERT (err == GLL_OK);

      err = gll_insert_right (p_obj, "wild");
      ASSERT (err == GLL_OK);

      err = gll_insert_right (p_obj, "world");
      ASSERT (err == GLL_OK);

      ASSERT (gll_is_empty (p_obj, &err) == 0);
      ASSERT (err == GLL_OK);

      /* --------------------------------------------
         current is now initialized
         -------------------------------------------- */

      err = gll_goto_head (p_obj);
      ASSERT (err == GLL_OK);

      {
         char s[128] = "";

         do
         {
            void const *p_data = gll_read_data (p_obj, &err);

            ASSERT (p_data != NULL);
            ASSERT (err == GLL_OK);

            strcat (s, p_data);

            err = gll_next (p_obj);

         }
         while (err == GLL_OK);

         ASSERT (strcmp (s, "Hellowildworld") == 0);
      }

      err = gll_goto_head (p_obj);
      ASSERT (err == GLL_OK);

      err = gll_next (p_obj);
      ASSERT (err == GLL_OK);

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (strcmp (p_data, "wild") == 0);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         ASSERT (err == GLL_OK);
         ASSERT (strcmp (p_data, "world") == 0);
      }

      {
         void const *p_data = gll_remove (p_obj, &err);
         PERR (err);
         ASSERT (err == GLL_OK);
         ASSERT (strcmp (p_data, "Hello") == 0);
      }

      /* --------------------------------------------
         current is not yet initialized
         -------------------------------------------- */

      gll_delete (p_obj), p_obj = NULL;
      PERR (err);
   }
   ASSERT (p_obj == NULL);
}

/* ---------------------------------------------------------------------
   test_5 ()
   ---------------------------------------------------------------------
   tests with three nodes and editing
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void test_5 (void)
{
   gll_s *p_obj = gll_create ();

   if (p_obj != NULL)
   {
      gll_err_e err;

      err = gll_insert_right (p_obj, "Hello");
      ASSERT (err == GLL_OK);

      err = gll_insert_right (p_obj, " ");
      ASSERT (err == GLL_OK);

      err = gll_insert_right (p_obj, "wild");
      ASSERT (err == GLL_OK);

      err = gll_insert_right (p_obj, " ");
      ASSERT (err == GLL_OK);

      err = gll_insert_right (p_obj, "world");
      ASSERT (err == GLL_OK);


      {
         char s[128] = "";

         err = gll_goto_head (p_obj);
         ASSERT (err == GLL_OK);
         do
         {
            void const *p_data = gll_read_data (p_obj, &err);

            ASSERT (p_data != NULL);
            ASSERT (err == GLL_OK);

            strcat (s, p_data);

            err = gll_next (p_obj);

         }
         while (err == GLL_OK);

         PRT (s);
         ASSERT (strcmp (s, "Hello wild world") == 0);
      }

      err = gll_goto_head (p_obj);
      ASSERT (err == GLL_OK);
      do
      {
         void const *p_data = gll_read_data (p_obj, &err);

         ASSERT (p_data != NULL);
         ASSERT (err == GLL_OK);

         if (strcmp (p_data, "wild") == 0)
         {
            p_data = gll_remove (p_obj, &err);
            ASSERT (err == GLL_OK);

            p_data = gll_remove (p_obj, &err);
            ASSERT (err == GLL_OK);
            break;
         }
         else
         {
            err = gll_next (p_obj);
         }
      }
      while (err == GLL_OK);

      {
         char s[128] = "";

         err = gll_goto_head (p_obj);
         ASSERT (err == GLL_OK);
         do
         {
            void const *p_data = gll_read_data (p_obj, &err);

            ASSERT (p_data != NULL);
            ASSERT (err == GLL_OK);

            strcat (s, p_data);

            err = gll_next (p_obj);

         }
         while (err == GLL_OK);

         PRT (s);
         ASSERT (strcmp (s, "Hello world") == 0);
      }


      gll_delete (p_obj), p_obj = NULL;
   }
   ASSERT (p_obj == NULL);
}
/* ---------------------------------------------------------------------
   test ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static int test (void)
{
   int ret = EXIT_SUCCESS;

/* identification test */
   printf ("Testing: %s %s\n", gll_sid (), gll_sver ());

   TEST (1);
   TEST (2);
   TEST (3);
   TEST (4);
   TEST (5);
   return ret;
}

/* ---------------------------------------------------------------------
   onexit ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void onexit (void)
{
   system ("pause");
}

/* entry points ======================================================== */

/* ---------------------------------------------------------------------
   main ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
int main (void)
{
   int ret = EXIT_SUCCESS;

#ifdef DBG_SYSALLOC
   char Trace[1 << 8];

   SYS_INIT (Trace, OFF);
#endif

   atexit (onexit);

   ret = test ();

#ifdef DBG_SYSALLOC
   sys_mem_trace ();
#endif

   return ret;
}

/* ---------------------------------------------------------------------
   Generated by NEW (c) ED 2.8
   Powered by C-code generator library  1.2
   --------------------------------------------------------------------- */
