/* ========================================================================== */
/*! \file
 * \brief Test of \c posix_snprintf() implementation
 *
 * Copyright (c) 2012-2020 by the developers. See the LICENSE file for details.
 */


/* ========================================================================== */
/* Include headers */

#include "posix.h"  /* Include this first because of feature test macros */

#include <stdio.h>

#include "test.h"
#include "test_snprintf.h"


/* ========================================================================== */
/*! \addtogroup TEST */
/*! @{ */


/* ========================================================================== */
/*! \brief Test \c posix_snprintf() implementation
 *
 * The following cases are tested:
 * - Literal percent conversion
 * - Signed integer conversion with long modifier
 * - Unsigned integer conversion with long modifier
 * - Unsigned integer conversion to hex
 * - Unsigned integer conversion to hex with long modifier
 * - Minimum field width padding with unsigned integer conversion
 * - Minimum field width zero padding with signed long integer conversion
 *   (on negative value)
 * - Minimum field width padding with signed long integer conversion
 *   (on negative value)
 * - Zero signed value without padding
 * - Zero unsigned value without padding
 * - Truncation of output
 * - Zero length (C99/POSIX.1-2001/SUSv4 semantics)
 * - Zero length and NULL pointer for buffer (C99/POSIX.1-2001/SUSv4 semantics)
 *
 * \return
 * - \c EXIT_SUCCESS on success
 * - \c EXIT_FAILURE on error
 */

int  test_snprintf(void)
{
   int  res = POSIX_EXIT_SUCCESS;
   char  buf[128];
   const char*  expected1 = "x1: 10, y2: 50%, eol";
   const char*  expected2 = "Long int: 100000";
   const char*  expected3 = "Unsigned long int: 3123456789";
   const char*  expected4 = "Fields width padding: 2013-01-05";
   const char*  expected5 = "Field width padding: -00100000";
   const char*  expected6 = "Field width padding:   -100000";
   const char*  expected7 = "Zero field: 0";
   const char*  expected8 = "Unsigned long int to hex: 0x8000100a";
   const char*  expected9 = "Unsigned int to hex: 0x0A55";
   const char*  expected10 = "AAA";  /* truncated */
   int  rv;

   /*
    * This test the following things:
    * - String conversion
    * - Signed integer conversion
    * - Literal percent conversion
    * - Intermediate text between conversions
    */
   rv = posix_snprintf(buf, 128,
                       "x%s: %u, y%s: %d%%, eol",
                       "1", 10U, "2", 50);
   if (0 > rv)
   {
      print_error("Negative return value");
      res = POSIX_EXIT_FAILURE;
   }
   else
   {
      if(strlen(expected1) != rv)
      {
         print_error("Length of result is not correct");
         res = POSIX_EXIT_FAILURE;
      }
      else if(strncmp(expected1, buf, 128))
      {
         print_error("Result is not correct");
         res = POSIX_EXIT_FAILURE;
      }
      if(res)
      {
         /* For debugging */
         fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
         fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected1);
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Signed long integer conversion
       */
      rv = posix_snprintf(buf, 128, "Long int: %ld", 100000L);
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(strlen(expected2) != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         else if(strncmp(expected2, buf, 128))
         {
            print_error("Result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         if(res)
         {
            /* For debugging */
            fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
            fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected2);
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Unsigned long integer conversion
       *   The test value does not fit into a 32 Bit signed variable
       */
      rv = posix_snprintf(buf, 128, "Unsigned long int: %lu", 3123456789UL);
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(strlen(expected3) != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         else if(strncmp(expected3, buf, 128))
         {
            print_error("Result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         if(res)
         {
            /* For debugging */
            fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
            fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected3);
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Pad minimum field width with zeros
       */
      rv = posix_snprintf(buf, 128, "Fields width padding: %04u-%02u-%02u",
                          2013, 1, 5);
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(strlen(expected4) != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         else if(strncmp(expected4, buf, 128))
         {
            print_error("Result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         if(res)
         {
            /* For debugging */
            fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
            fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected4);
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Pad minimum field width with leading zeros on negative value
       */
      rv = posix_snprintf(buf, 128, "Field width padding: %09ld", -100000L);
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(strlen(expected5) != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         else if(strncmp(expected5, buf, 128))
         {
            print_error("Result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         if(res)
         {
            /* For debugging */
            fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
            fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected5);
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Pad minimum field width with spaces before sign on negative value
       */
      rv = posix_snprintf(buf, 128, "Field width padding: %9ld", -100000L);
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(strlen(expected6) != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         else if(strncmp(expected6, buf, 128))
         {
            print_error("Result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         if(res)
         {
            /* For debugging */
            fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
            fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected6);
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Zero signed value without padding
       * - Zero unsigned value without padding
       */
      rv = posix_snprintf(buf, 128, "Zero field: %d", 0);
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(strlen(expected7) != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         else if(strncmp(expected7, buf, 128))
         {
            print_error("Result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         if(res)
         {
            /* For debugging */
            fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
            fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected7);
         }
         if(res)
         {
            rv = posix_snprintf(buf, 128, "Zero field: %u", 0U);
            if(strlen(expected7) != rv)
            {
               print_error("Length of result is not correct");
               res = POSIX_EXIT_FAILURE;
            }
            else if(strncmp(expected7, buf, 128))
            {
               print_error("Result is not correct");
               res = POSIX_EXIT_FAILURE;
            }
            if(res)
            {
               /* For debugging */
               fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
               fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected7);
            }
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Unsigned long integer conversion to hexadecimal
       *   The test value does not fit into a 32 Bit signed variable
       */
      rv = posix_snprintf(buf, 128, "Unsigned long int to hex: 0x%lx",
                          0x8000100AUL);
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(strlen(expected8) != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         else if(strncmp(expected8, buf, 128))
         {
            print_error("Result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         if(res)
         {
            /* For debugging */
            fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
            fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected8);
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Unsigned integer conversion to hexadecimal (with capital letters)
       * - Pad minimum field width with leading zeros
       */
      rv = posix_snprintf(buf, 128, "Unsigned int to hex: 0x%04X", 0xA55U);
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(strlen(expected9) != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         else if(strncmp(expected9, buf, 128))
         {
            print_error("Result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         if(res)
         {
            /* For debugging */
            fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
            fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected9);
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Truncation of output
       */
      rv = posix_snprintf(buf, 4, "AAAbbb (truncation)");
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(19 != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         else if(strncmp(expected10, buf, 128))
         {
            print_error("Result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
         if(res)
         {
            /* For debugging */
            fprintf(stderr, TEST_TAB "Result is: \"%s\"\n", buf);
            fprintf(stderr, TEST_TAB "Should be: \"%s\"\n", expected10);
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Truncation of output with zero buffer size
       *   Allowed with C99/POSIX.1-2001/SUSv4 semantics
       */
      rv = posix_snprintf(buf, 0, "AAAbbb (truncation)");
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(19 != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
      }
   }

   if(POSIX_EXIT_SUCCESS == res)
   {
      /*
       * This test the following things:
       * - Truncation of output with zero buffer size and NULL pointer
       *   Allowed with C99/POSIX.1-2001/SUSv4 semantics
       */
      rv = posix_snprintf(NULL, 0, "AAAbbb (truncation)");
      if (0 > rv)
      {
         print_error("Negative return value");
         res = POSIX_EXIT_FAILURE;
      }
      else
      {
         if(19 != rv)
         {
            print_error("Length of result is not correct");
            res = POSIX_EXIT_FAILURE;
         }
      }
   }

   return(res);
}


/*! @} */

/* EOF */
