/* t4expr.c   (c)Copyright Sequiter Software Inc., 1990-1994. All rights reserved.
    Tests Code Base Expression Evaluation Routines.
    */

#include "d4all.h"
#ifdef __TURBOC__
#pragma hdrstop
#endif

#include "t4test.h"

 static FIELD4INFO testfields[] =
{
  /* name, type, len_field, dec  */
{"N1",   'F',      5,    2,    },
{"N2",   'N',     10,    0,    },
{"N3",   'N',      8,    3,    },
{"N4",   'N',     19,   10,    },
{"C1",   'C',     10,    0,    },
{"C2",   'C',     10,    0,    },
{"C3",   'C',     10,    0,    },
{"C4",   'C',     15,    0,    },
{"C5",   'C',     15,    0,    },
{"C6",   'C',      5,    0,    },
{"D1",   'D',      8,    0,    },
{"D2",   'D',      8,    0,    },
{"L1",   'L',      1,    0,    },
{"L2",   'L',      1,    0,    },
{0,0,0,0,}
};

typedef struct test_expr_st
{
  char  expr[30] ;
  char  result[50] ;
  char  result_type ;
}  TEST_EXPR ;

CODE4 cb;
DATA4 *data;

/* this is required because of potential 'double return'
   problems that may occur in cross-platform DLL usage */
static TEST_EXPR test_expr[] =
{
{  ".NOT. .F.                    ",
   "1                            ",
   r4log
   },

{  "5>4.AND.6.7>4.3              ",
   "1                            ",
   r4log
   },


{  "\"NEW   \"  -  \"ME \"       ",
   "NEWME    \0                  ",
   r4str
   },

{  "'NEW   '  -  'ME '           ",
   "NEWME    \0                  ",
   r4str
   },

   /* 5 */
{  ".T. .AND. .F.                ",
   "0                            ",
   r4log
   },

{  "IIF(C1=\"SMUR\",\"TRUE\",\"FALS\")",
   "FALS\0                       ",
   r4str
   },

{  "((((7))))*(1+2)              ",
   "21                           ",
   r4num_doub
   },

{  "N1+N2                        ",
   "12                           ",
   r4num_doub
   },

{  "N1-N2                        ",
   "8                            ",
   r4num_doub
   },

   /* 10 */
{  "N1*N2                        ",
   "20                           ",
   r4num_doub
   },

{  "N1/N2                        ",
   "5                            ",
   r4num_doub
   },

{  "C1+C2                        ",
   "character1CHARACTER2\0        ",
   r4str
   },

{  "C1-C2                        ",
   "character1CHARACTER2\0        ",
   r4str
   },

{  "C1-C4-C5                     ",
   "character11988020119880323              \0",
   r4str
   },

   /* 15 */
{  "C5-C1-C3-C2                  ",
   "19880323character1ChArAcTeR3CHARACTER2       \0",
   r4str
   },

{  "C1=C2                        ",
   "0                            ",
   r4log
   },

{  "C1=C3                        ",
   "0                            ",
   r4log
   },

{  "C1>C2                        ",
   "1                            ",
   r4log
   },

{  "C1<C2                        ",
   "0                            ",
   r4log
   },

   /* 20 */
{  "C1<>C2                       ",
   "1                            ",
   r4log
   },

{  "C1#C2                        ",
   "1                            ",
   r4log
   },

{  "C1#C2                        ",
   "1                            ",
   r4log
   },

{  "C1<>C3                       ",
   "1                            ",
   r4log
   },

{  "C1$C2                        ",
   "0                            ",
   r4log
   },

   /* 25 */
{  "\"ST\"$\"MOST\"                  ",
   "1                            ",
   r4log
   },

#ifndef __SC__
#ifdef _MSC_VER
#pragma warning( disable : 4129 )
#endif
{  "\[ST\]$\[MOST\]                  ",
   "1                            ",
   r4log
   },
#ifdef _MSC_VER
#pragma warning( default : 4129 )
#endif

#endif

#ifdef S4GERMAN
{  "CTOD(\"01.02.88\")             ",
   "19880201\0                    ",
   r4date_doub
   },

{  "DTOC(D2)                     ",
   "23.03.88\0                    ",
   r4str
   },
#else
{  "CTOD(\"02/01/88\")             ",
   "19880201\0                    ",
   r4date_doub
   },

{  "DTOC(D2)                     ",
   "03/23/88\0                    ",
   r4str
   },
#endif

{  "STOD(C4)                     ",
   "19880201\0                    ",
   r4date_doub
   },

   /* 30 */
{  "DTOS(D2)                     ",
   "19880323\0                    ",
   r4str
   },

{  "D1=STOD(C4)                  ",
   "1                            ",
   r4log
   },

{  "C5=DTOS(D2)                  ",
   "1                            ",
   r4log
   },

{  "IIF(C1=\"SMUR\",\"TRUE\",\"FALS\")",
   "FALS\0                         ",
   r4str
   },

{  "RECCOUNT()                   ",
   "1                            ",
   r4num_doub
   },

   /* 35 */
{  "RECNO()                      ",
   "1                            ",
   r4num_doub
   },

{  "STR(5.7,4,2)                 ",
   "5.70\0                        ",
   r4str
   },

{  "VAL(\"2323\")                  ",
   "2323                         ",
   r4num_doub
   },

{  "SUBSTR(C1,2,2)               ",
   "ha\0                          ",
   r4str
   },

{  "C1 + SUBSTR(C1,2,2)          ",
   "character1ha\0                ",
   r4str
   },

{  "3*4-2                        ",
   "10                           ",
   r4num_doub
   },

{  "L1                           ",
   "0                            ",
   r4log
   },

{  ".NOT. .T.                    ",
   "0                            ",
   r4log
   },

{  ".NOT. .F.                    ",
   "1                            ",
   r4log
   },

{  ".T.                          ",
   "1                            ",
   r4log
   },

{  ".T. .OR. .F.                 ",
   "1                            ",
   r4log
   },

{  ".T. .AND. .F.                ",
   "0                            ",
   r4log
   },

{  "\"A \" + \"B   \"                ",
   "A B   \0                      ",
   r4str
   },

{  "\"NEW   \"  -  \"ME \"           ",
   "NEWME    \0                   ",
   r4str
   },

{  "\"    \" - \" ab\"               ",
   " ab    \0                     ",
   r4str
   },

{  "((((7))))*(1+2)              ",
   "21                           ",
   r4num_doub
   },

{  " IIF( .F. , 1, 2)            ",
   "2                            ",
   r4num_doub
   },

{  "   IIF ( .T., \"G\", \"B\" )",
   "G\0                      ",
   r4str
   },



{  "(4*3)<=(2*6)                 ",
   "1                            ",
   r4log
   },

{  " .F. .AND. .F. .OR. .T.      ",
   "1                            ",
   r4log
   },

{  " .NOT. .F. .AND. .F.         ",
   "0                            ",
   r4log
   },

{  " .NOT. .F. .AND. .F. .OR. .T.",
   "1                            ",
   r4log
   },

{  " .NOT. 3 > 2                 ",
   "0                            ",
   r4log
   },

{  "   C6+                  DEL()",
   "CHAR *\0                      ",
   r4str
   },

{  "DELETED()                    ",
   "1                            ",
   r4log
   },

{  "MONTH(DATE()   )             ",
   "7                            ",
   1
   },

{  "RECCOUNT() + 3               ",
   "4                            ",
   r4num_doub
   },

{  "RECNO()                      ",
   "1                            ",
   r4num_doub
   },

{  "STR(5.73,6,3)                ",
   " 5.730\0                      ",
   r4str
   },

{  "STR(9.643,3)                 ",
   " 10\0                        ",
   r4str
   },

{  "YEAR(D2    )                 ",
   "1988                         ",
   r4num_doub
   },

{  "DATE()                       ",
   "                             ",
   1
   },

{  "TIME()                       ",
   "                             ",
   2
   },

#ifndef S4NO_POW
#ifndef __ZTC__

   /* Zortech fails because Zortech 'pow' does not round the result. */
{  "N1^N2                        ",
   "100                          ",
   r4num_doub
   },

{  "2^4                          ",
   "16                           ",
   r4num_doub
   },

{  "3**5                         ",
   "243                          ",
   r4num_doub
   },
#endif
#endif

#ifndef S4UNIX
#ifndef __ZTC__
#ifndef __HIGHC__
{  "N4-N3                        ",
   "986419.754001                ",
   r4num_doub
   },

{  "STR(22.2,5,1)                ",
   " 22.2\0                       ",
   r4str
   },

{  "STR(21.5,6,0)                ",
   "    22\0                      ",
   r4str
   },
#endif
#endif
#endif

#ifndef S4UNIX
#ifndef S4NO_POW
#ifndef __HIGHC__
#ifndef __ZTC__
{  "((13))**7+13                 ",
   "62748530                     ",
   r4num_doub
   },
#endif

{  "((13))^7+13                  ",
   "62748530                     ",
   r4num_doub
   },
#endif
#endif
#endif

{  "STR(22.2,6,2)+STR(11.1,7,1)  ",
   " 22.20   11.1\0               ",
   r4str
   },

{  "STR(1.5,3,1)+STR(1.9345,4,2) ",
   "1.51.93\0                     ",
   r4str
   },

{  "'ooga'+STR(1.9345,4,2) ",
   "ooga1.93\0                    ",
   r4str
   },

{  "\0                            ",
   "                             ",
   '\0'
   },
 };

static int do_test( D4DISPLAY *disp )
{
  int i, str_len ;
  char logical;
  double d ;
  EXPR4 *ptr ;
  char *buf, *key_result;
  char date_buf[20] ;

#ifdef S4WINDOWS
  cb.hWnd = (unsigned) disp->hWnd ;
#ifdef S4DLL
  cb.hInst = (unsigned) disp->hInst ;
#endif
#endif

  cb.safety = '\0';

#ifdef S4OPEN_FILE
  data = d4open( &cb, "T4EXPR" ) ;
#else
  data = d4create( &cb, "T4EXPR", testfields, 0);
#endif

  if ( cb.error_code || data == 0 )
    t4severe( t4err_data, "01" ) ;

  d4opt_start( &cb ) ;

  if ( d4append_start(data, 0) < 0)
    t4severe( t4err_append, "02" ) ;

  f4assign( (d4field(data, "C1")), "character1");
  f4assign( (d4field(data, "C2")), "CHARACTER2");
  f4assign( (d4field(data, "C3")), "ChArAcTeR3");
  f4assign( (d4field(data, "C4")), "19880201");
  f4assign( (d4field(data, "C5")), "19880323");
  f4assign( (d4field(data, "C6")), "CHAR");

  d = 10.0 ;
  f4assign_double( (d4field(data, "N1")), d ) ;
  d = 2.0 ;
  f4assign_double( (d4field(data, "N2")), d );
  d = 1234.567 ;
  f4assign_double( (d4field(data, "N3")), d );
  d = 987654.321001 ;
  f4assign_double( (d4field(data, "N4")), d );

  f4assign( ( d4field(data, "D1" ) ), "19880201" ) ;
  f4assign( ( d4field(data, "D2" ) ), "19880323" ) ;
  logical = 'F';
  f4assign( ( d4field( data, "L1" ) ), &logical ) ;
  logical = 'T';
  f4assign( ( d4field( data, "L2" ) ), &logical ) ;
  d4delete( data ) ;

  if ( d4append( data ) < 0 )
    t4severe( t4err_append, "03" ) ;

  for ( i=0; test_expr[i].result_type != '\0'; i++ )
  {
    if ( d4display_quit( disp ) )
      return 1 ;

    d4display_num( disp, i, 1 ) ;
    d4display_str( disp,  ") On Expression: ", 0 ) ;
    d4display_str( disp, test_expr[i].expr, 0 ) ;
    ptr = expr4parse(data, test_expr[i].expr ) ;

    if ( ptr == (void *) 0 )
      t4severe( t4err_expr, "04" ) ;

    if (expr4vary(ptr, &buf) < 0)
      t4severe( t4err_expr, "05" ) ;

    if ( test_expr[i].result_type == 1 )/* DATE() function, cannot compare */
    {
      date4assign(buf, (long) *(double *)buf ) ;
      buf[8] = '\0' ;
      date4format(buf, date_buf, "MMM DD/CCYY" ) ;
      d4display_str( disp,  "", 1 ) ;
      d4display_str( disp, "DATE:", 0) ;
      d4display_str( disp, date_buf, 1) ;
    }

    if ( test_expr[i].result_type == 2 )/* TIME() function, cannot compare */
    {
      d4display_str( disp, "TIME:", 0) ;
      d4display_str( disp, buf, 1) ;
      d4display_str( disp,  "", 1 ) ;
    }

    if ( test_expr[i].result_type > 10 )
    {
      if ( (char) expr4type(ptr) != test_expr[i].result_type )
        t4severe( t4err_expr, "06" ) ;

      switch ( (char) expr4type(ptr) )
      {
      case r4str :
        str_len = expr4key( ptr, &key_result ) ;
        if ( memcmp( buf, test_expr[i].result, str_len ) != 0 )
        {
          e4describe( &cb, 0, "t4expr  EXPR(r4str):", test_expr[i].expr, (char *) 0 ) ;
          e4exit( &cb) ;
        }
        if ( strcmp( key_result, test_expr[i].result) != 0 )
        {
          e4describe( &cb, 0, "t4expr  EXPR(r4str):", test_expr[i].expr, (char *) 0 ) ;
          e4exit( &cb) ;
        }
        break ;


      case r4log :
        if ( ( *(int*) buf && !(c4atoi(test_expr[i].result,1)) )  ||
            ( !*(int*) buf && (c4atoi(test_expr[i].result,1)) ) )
        {
          e4describe( &cb, 0, "t4expr  EXPR(r4log):", test_expr[i].expr, (char *) 0 ) ;
          e4exit( &cb) ;
        }
        break;

      case r4num_doub :

#ifndef S4WINDOWS
        c4atod2(test_expr[i].result, 30, &d );
        if ( *(double *) buf != d )
        {
          e4describe( &cb, 0, "t4expr  EXPR(r4num_doub):", test_expr[i].expr, (char *) 0 ) ;
          e4exit( &cb) ;
        }
#endif
        break;

      case r4date_doub :
      {
        char buf2[8] ;
        long d_ptr ;

        d_ptr = (long) *(double *) buf;

        date4assign( buf2, d_ptr ) ;

        if ( memcmp(  buf2, test_expr[i].result, 8) != 0 )
        {
          e4describe( &cb, 0, "t4expr  EXPR)r4date_doub):", test_expr[i].expr, (char *) 0 ) ;
          e4exit( &cb) ;
        }
        break;
      }
      }
    }
    expr4free(ptr) ;
  }

  if ( d4close_all( &cb ) != 0 )
    t4severe( t4err_close, "07" ) ;
  return 0 ;
}


static int  test_with_mem_check( D4DISPLAY *disp )
{
  d4init( &cb ) ;

  if ( do_test( disp ) )
    return 1 ;

#ifndef S4TEST_KEEP_FILES
  u4remove( "T4EXPR.dbf" ) ;
#endif

  d4init_undo(&cb) ;
  mem4reset() ;

#ifdef S4DEBUG
  mem4check_memory() ;

#ifndef S4DLL
  if ( mem4free_check(100) != 0 )
    t4severe( t4err_memory, "08" ) ;
#endif
#endif

  return 0 ;
}


int S4FUNCTION t4test( D4DISPLAY *disp )
{
  if ( test_with_mem_check( disp ) )
    t4severe( t4err_general, "09" ) ;
  if ( test_with_mem_check( disp ) )
    t4severe( t4err_general, "10" ) ;
  if ( test_with_mem_check( disp ) )
    t4severe( t4err_general, "11" ) ;

  d4display_str( disp, "T4EXPR:   SUCCESS", 1) ;
  d4display_str( disp, "", 1) ;
  return 1 ;
}