/* A little program for testing the Intoids.library.  By AGMS. */
/* $Header: Big:Programming/C/Intoids/Test/RCS/Test.c,v 1.8 1997/02/12 17:58:24 AGMS Exp $ */

#include <stdio.h>
#include <stdlib.h>  /* For atexit */
#include <string.h>
#include <proto/exec.h>
#include <proto/Intoids.h>

struct Library *IntoidsBase;



/******************************************************************************
 * Prints the binary representation of an Intoid.
 */

void DumpIntoid (Intoid IntegerA)
{
  typedef struct IntRepStruct
  {
    unsigned short  currentLength;    /* Number of entries in numberArray. */
    BOOL            positiveSign;     /* 1 means >= 0; 0 means < 0. */
    unsigned short  allocatedLength;  /* 0 means static.  Number of shorts. */
    unsigned short  numberArray [1];  /* least significant value in [0]. */
  } IntRep, *IntRepPointer;

  int           i;
  IntRepPointer MyIntRep;

  if ((long) IntegerA & 1) /* A small int */
    printf ("%lX:%ld", (long) IntegerA, ((long) IntegerA) >> 1);
  else if (IntegerA == 0) /* Not a number, null number. */
    printf ("NAN");
  else if ((((long) IntegerA) & 3) == 0) /* A pointer to Intrep. */
  {
    MyIntRep = (IntRepPointer) IntegerA;
    printf ("%08lX->%d/%d%c",(long) MyIntRep,
    (int) MyIntRep->currentLength, (int) MyIntRep->allocatedLength,
    MyIntRep->positiveSign ? '+' : '-');
    for (i = MyIntRep->currentLength - 1; i >= 0; --i)
      printf ("%04X", (int) MyIntRep->numberArray[i]);
    for (i = MyIntRep->currentLength; i < MyIntRep->allocatedLength; i++)
      if (MyIntRep->numberArray[i] != 0)
      {
        printf ("\n**** BUG: Non-zero word in unused but allocated part. ****\n");
        break;
      }
  }
  else /* A special code. */
    printf ("SC%d", (int) (((long) IntegerA) >> 2));
}



/******************************************************************************
 * Converts the string to an Intoid, a long, a string and portable number
 * format and converts it back to see if it got it right.
 */

void TestConversions (char *InputString)
{
  Intoid  IntoidA;
  Intoid  IntoidB;
  long    BufferNeeded;
  ULONG   ByteCount;
  char    MyBuffer[80];
  long    NewLong;
  char   *NextLetter;

  /* String conversion tests. */

  IntoidA = AsciiToIntoid (InputString, &NextLetter,
  0 /* default base */, NULL);

  BufferNeeded = IntoidToAscii (IntoidA, MyBuffer, sizeof (MyBuffer), 10);
  printf ("Input \"%s\" becomes \"%s\", leftover \"%s\"\n",
  InputString ? InputString : "NULL",
  MyBuffer,
  NextLetter ? NextLetter : "NULL");
  printf ("intoid representation is ");
  DumpIntoid (IntoidA);
  printf ("\n");

  if (BufferNeeded != strlen (MyBuffer) + 1)
    printf ("**** BUG: IntoidToAscii returns %ld, not %ld. ****\n",
    BufferNeeded, (long) strlen (MyBuffer) + 1);

  if (InputString != NULL)
    BufferNeeded = strlen (InputString);
  else
    BufferNeeded = 0;
  if (NextLetter < InputString || NextLetter > InputString + BufferNeeded)
    printf ("**** BUG: AsciiToIntoid next letter out of range. ****\n");

  IntoidB = AsciiToIntoid (MyBuffer, NULL, 10, NULL);

  if (CompareIntoids (IntoidA, IntoidB) != 0)
    printf ("**** BUG: AsciiToIntoid and back didn't work. ****\n");

  /* Long conversion tests. */

  NewLong = IntoidToLong (IntoidA);
  printf ("as a long $%lX (%ld)\n", NewLong, NewLong);

  IntoidB = LongToIntoid (NewLong, IntoidB);
  if (CompareIntoids (IntoidA, IntoidB) != 0)
    printf ("**** BUG: Intoid<->Long conversion didn't work. ****\n");

  if (!IntoidFitsInLong (IntoidB))
    printf ("**** BUG: Claims %ld doesn't fit in a long after conversion! ****\n",
    NewLong);

  /* Portable integer tests. */

  if (!IntoidToPortableIntViaBuffer (IntoidA, &ByteCount, MyBuffer, sizeof (MyBuffer)))
    printf ("**** BUG: Can't convert to a portable integer. ****\n");

  printf ("portable int format is %ld bytes:", ByteCount);
  for (NewLong = 0; NewLong < ByteCount; NewLong++)
    printf (" %02X", (int) (UBYTE) MyBuffer [NewLong]);
  printf ("\n");

  NewLong = PortableIntSizeOfIntoid (IntoidA);
  if (ByteCount != NewLong)
    printf ("**** BUG: Portable length estimate from Intoid is %ld, not %ld. ****\n",
    NewLong, ByteCount);

  NewLong = PortableIntLengthViaBuffer (MyBuffer, sizeof (MyBuffer));
  if (NewLong != ByteCount)
    printf ("**** BUG: Length of portable in buffer is %ld, not %ld. ****\n",
    NewLong, ByteCount);

  NewLong = ByteCount;
  IntoidB = PortableIntToIntoidViaBuffer (MyBuffer, sizeof (MyBuffer),
  &ByteCount, IntoidB);

  if (ByteCount != NewLong)
    printf ("**** BUG: Portable Int to Intoid length is %ld, not %ld. ****\n",
    ByteCount, NewLong);

  if (CompareIntoids (IntoidA, IntoidB) != 0)
    printf ("**** BUG: Portable Integer conversion didn't work. ****\n");

  FreeIntoid (IntoidA);
  FreeIntoid (IntoidB);

  printf ("\n");
}



/******************************************************************************
 * Test the comparison function, and addition and subtraction.
 */

static void TestComparison (char *String1, char *String2)
{
  Intoid  IntegerA;
  Intoid  IntegerB;
  Intoid  IntegerC;
  char    MyBufferA[80];
  char    MyBufferB[80];
  long    Result;

  IntegerA = AsciiToIntoid (String1, NULL, 0 /* default base */, NULL);
  IntegerB = AsciiToIntoid (String2, NULL, 0 /* default base */, NULL);
  IntegerC = NULL;

  /* Subtraction test. */

  IntegerC = SubtractIntoids (IntegerA, IntegerB, IntegerC);
  IntoidToAscii (IntegerC, MyBufferA, sizeof (MyBufferA), 10);
  printf ("%s - %s = %s, ", String1, String2, MyBufferA);
  DumpIntoid (IntegerC);
  printf ("\n");

  IntegerC = AddIntoids (IntegerC, IntegerB, IntegerC);
  IntoidToAscii (IntegerC, MyBufferB, sizeof (MyBufferB), 10);
  if (CompareIntoids (IntegerA, IntegerC) != 0)
    printf ("**** BUG: %s - %s + %s = %s, not %s. ****\n",
    String1, String2, String2, MyBufferB, String1);

  /* Addition test. */

  IntegerC = AddIntoids (IntegerA, IntegerB, IntegerC);
  IntoidToAscii (IntegerC, MyBufferA, sizeof (MyBufferA), 10);
  printf ("%s + %s = %s, ", String1, String2, MyBufferA);
  DumpIntoid (IntegerC);
  printf ("\n");

  IntegerC = SubtractIntoids (IntegerC, IntegerA, IntegerC);
  IntoidToAscii (IntegerC, MyBufferB, sizeof (MyBufferB), 10);
  if (CompareIntoids (IntegerB, IntegerC) != 0)
    printf ("**** BUG: %s + %s - %s = %s, not %s. ****\n",
    String1, String2, String1, MyBufferB, String2);

  /* Comparison tests. */

  Result = CompareIntoids (IntegerA, IntegerB);
  printf ("Signed comparison: %s %c %s\n",
  String1,
  (Result < 0) ? '<' : ((Result == 0) ? '=' : '>'),
  String2);

  Result = CompareIntoidMagnitudes (IntegerA, IntegerB);
  printf ("Magnitude comparison: %s %c %s\n",
  String1,
  (Result < 0) ? '<' : ((Result == 0) ? '=' : '>'),
  String2);

  FreeIntoid (IntegerA);
  FreeIntoid (IntegerB);
  FreeIntoid (IntegerC);

  printf ("\n");
}



/******************************************************************************
 * Test multiplication and division.
 */

void TestMultiplication (char *String1, char *String2)
{
  Intoid  IntegerA;
  Intoid  IntegerB;
  Intoid  IntegerC;
  Intoid  IntegerD;
  char    MyBufferA[80];
  char    MyBufferB[80];

  IntegerA = AsciiToIntoid (String1, NULL, 0 /* default base */, NULL);
  IntegerB = AsciiToIntoid (String2, NULL, 0 /* default base */, NULL);

  IntegerC = MultiplyIntoids (IntegerA, IntegerB, NULL);
  IntegerD = NULL;

  IntoidToAscii (IntegerC, MyBufferA, sizeof (MyBufferA), 10);
  printf ("%s * %s = %s, ", String1, String2, MyBufferA);
  DumpIntoid (IntegerC);
  printf ("\n");

  if (IntegerA != SmallIntToIntoid (0) && IntegerA != NULL)
  {
    IntegerD = DivideIntoids (IntegerC, IntegerA, IntegerD);
    if (CompareIntoids (IntegerB, IntegerD) != 0)
    {
      IntoidToAscii (IntegerC, MyBufferA, sizeof (MyBufferA), 10);
      IntoidToAscii (IntegerD, MyBufferB, sizeof (MyBufferB), 10);
      printf ("**** BUG: Division of %s by %s gives %s, not %s ****\n",
      MyBufferA, String1, MyBufferB, String2);
    }
  }

  if (IntegerB != SmallIntToIntoid (0) && IntegerB != NULL)
  {
    IntegerD = DivideIntoids (IntegerC, IntegerB, IntegerD);
    if (CompareIntoids (IntegerA, IntegerD) != 0)
    {
      IntoidToAscii (IntegerC, MyBufferA, sizeof (MyBufferA), 10);
      IntoidToAscii (IntegerD, MyBufferB, sizeof (MyBufferB), 10);
      printf ("**** BUG: Division of %s by %s gives %s, not %s ****\n",
      MyBufferA, String2, MyBufferB, String1);
    }
  }

  /* And now for the division test. */

  IntegerC = DivideIntoids (IntegerA, IntegerB, IntegerC);
  if (IntegerC == NULL)
  {
    printf ("Error reported during division: \"%s\"\n",
    GetLastIntoidErrorMessage ());
  }
  IntoidToAscii (IntegerC, MyBufferA, sizeof (MyBufferA), 10);
  printf ("%s / %s = %s, ", String1, String2, MyBufferA);
  DumpIntoid (IntegerC);
  printf ("\n");

  if (IntegerC != SmallIntToIntoid (0) && IntegerC != NULL)
  {
    if (SignOfIntoid (IntegerA) * SignOfIntoid (IntegerB) !=
    SignOfIntoid (IntegerC))
      printf ("**** BUG: Result of division has wrong sign. ****\n");

    IntegerD = MultiplyIntoids (IntegerC, IntegerB, IntegerD);
    IntegerD = SubtractIntoids (IntegerA, IntegerD, IntegerD);
    IntoidToAscii (IntegerD, MyBufferB, sizeof (MyBufferB), 10);
    if (CompareIntoidMagnitudes (IntegerB, IntegerD) < 0)
      printf ("**** BUG: %s - (%s * %s) is %s, magnitude is bigger than %s. ****\n",
      String1, String2, MyBufferA, MyBufferB, String2);
  }

  FreeIntoid (IntegerA);
  FreeIntoid (IntegerB);
  FreeIntoid (IntegerC);
  FreeIntoid (IntegerD);

  printf ("\n");
}



/******************************************************************************
 * Test squaring of a number.
 */

void TestSquaring (STRPTR String)
{
  Intoid  IntegerA;
  Intoid  IntegerB;
  Intoid  IntegerC;
  char    MyBufferA[80];
  char    MyBufferB[80];

  IntegerA = AsciiToIntoid (String, NULL, 0 /* default base */, NULL);
  IntegerB = MultiplyIntoids (IntegerA, IntegerA, NULL);
  IntegerC = CopyIntoid (IntegerB, NULL);

  IntoidToAscii (IntegerB, MyBufferA, sizeof (MyBufferA), 10);
  printf ("%s squared = %s, ", String, MyBufferA);
  DumpIntoid (IntegerB);
  printf ("\n");

  IntegerB = DivideIntoids (IntegerB, IntegerA, IntegerB);
  if (CompareIntoids (IntegerA, IntegerB) != 0)
  {
    IntoidToAscii (IntegerB, MyBufferB, sizeof (MyBufferB), 10);
    printf ("**** BUG: Division of %s by %s gives %s, not %s ****\n",
    MyBufferA, String, MyBufferB, String);
  }

  IntegerA = MultiplyIntoids (IntegerA, IntegerA, IntegerA);
  if (CompareIntoids (IntegerC, IntegerA) != 0)
  {
    IntoidToAscii (IntegerA, MyBufferB, sizeof (MyBufferB), 10);
    printf ("**** BUG: Second squaring technique gives %s, not %s ****\n",
    MyBufferB, MyBufferA);
  }

  FreeIntoid (IntegerA);
  FreeIntoid (IntegerB);
  FreeIntoid (IntegerC);

  printf ("\n");
}



/******************************************************************************
 * Called when the program exits.  Close library etc.
 */

void CleanUp (void)
{
  printf ("Running CleanUp function.\n");

  if (IntoidsBase != NULL)
  {
    CloseLibrary (IntoidsBase);
    IntoidsBase = NULL;
    printf ("Closed " IntoidsName "\n");
  }
}



/******************************************************************************
 * The main program.  Open library, do tests, close library.
 */

int main (void)
{
  STRPTR      Credits;
  STRPTR      Infinity;
  char        MinusInfinity [80];
  STRPTR      NotANumber;

  atexit (CleanUp);

  IntoidsBase = OpenLibrary (IntoidsName, 0);
  if (IntoidsBase == NULL)
  {
    printf ("Sorry, unable to open " IntoidsName ".\n");
    return 20;
  }

  NotANumber = GetIntoidsMessage (MSG_INTOIDS_NOT_A_NUMBER);
  Infinity = GetIntoidsMessage (MSG_INTOIDS_INFINITY);
  strcpy (MinusInfinity + 1, Infinity);
  MinusInfinity[0] = '-';

  printf ("Here are the Intoids.library credits:\n");

  GetLastIntoidErrorMessage ();  /* Reset the error message to credits. */
  Credits = GetLastIntoidErrorMessage ();
  printf (Credits);


  TestConversions ("0");
  TestConversions ("-1L");
  TestConversions ("1 This is after.");
  TestConversions ("-0x7FFFFFFF");
  TestConversions ("-0x80000000");
  TestConversions ("-0x80000001");
  TestConversions ("+0x7FFFFFFF");
  TestConversions ("+0x80000000");
  TestConversions ("+0x80000001");
  TestConversions ("0x3FFFFFFF");
  TestConversions ("0x40000000");
  TestConversions ("-0x3FFFFFFF");
  TestConversions ("-0x40000000");
  TestConversions ("-0x40000001");
  TestConversions ("0xBFFFFFFF");
  TestConversions ("0xFFFE");
  TestConversions ("0xFFFF");
  TestConversions ("-0xFFFF");
  TestConversions ("0x10000");
  TestConversions ("-0x10000");
  TestConversions ("127");
  TestConversions ("128");
  TestConversions ("129");
  TestConversions ("254");
  TestConversions ("255");
  TestConversions ("256");
  TestConversions ("-105");
  TestConversions ("-106");
  TestConversions ("-107");
  TestConversions ("-127");
  TestConversions ("-128");
  TestConversions ("-129");
  TestConversions ("-254");
  TestConversions ("-255");
  TestConversions ("-256");
  TestConversions ("The next one will be a NULL pointer.");
  TestConversions (NULL);
  TestConversions ("100000");
  TestConversions ("-100000");
  TestConversions (" 1000000000000Space in front.");
  TestConversions ("\t-1000000000000Tab in front.");
  TestConversions ("\t 0x80000000Tab and space.");
  TestConversions ("0xc0000000");
  TestConversions ("00000000000000000000000000000000000000000100Lots of leading zeroes, base 8.");
  TestConversions (Infinity);
  TestConversions (MinusInfinity);
  TestConversions (NotANumber);
  TestConversions ("0x1122334455667788");
  TestConversions ("-0x112233445566778899");
  TestConversions ("-0x11223344556677889900");
  TestConversions ("-123456 Next we have 254, 255 and 256 byte long numbers.");
  TestConversions ("0x112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEE");
  TestConversions ("0x112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF");
  TestConversions ("0x112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00");

  TestComparison ("0", "0");
  TestComparison ("10", "8");
  TestComparison ("10", "10");
  TestComparison ("10", "11");
  TestComparison ("10", "12345678901234567890");
  TestComparison ("10", "-12345678901234567890");
  TestComparison ("-10", "12345678901234567890");
  TestComparison ("-10", "-12345678901234567890");
  TestComparison ("1000000000000000000", "1000000000000000000");
  TestComparison ("1000000000000000000", "1000000000000000007");
  TestComparison ("1000000000000000007", "1000000000000000000");
  TestComparison ("-1000000000000000000", "1000000000000000000");
  TestComparison ("1000000000000000000", "-1000000000000000000");
  TestComparison ("-1000000000000000000", "-1000000000000000000");
  TestComparison ("-1000000000000000007", "-1000000000000000000");
  TestComparison ("-1000000000000000000", "-1000000000000000007");
  TestComparison ("-10", Infinity);
  TestComparison ("10", Infinity);
  TestComparison ("-10", MinusInfinity);
  TestComparison ("10", MinusInfinity);
  TestComparison ("146237845623784678320", Infinity);
  TestComparison (MinusInfinity, Infinity);
  TestComparison (Infinity, MinusInfinity);
  TestComparison (Infinity, Infinity);
  TestComparison (MinusInfinity, MinusInfinity);
  TestComparison ("0xFFFF", "1");
  TestComparison ("0xFFFFFFFF", "1");
  TestComparison ("0xFFFFFFFFFFFF", "1");
  TestComparison ("0xFFFFFFFFFFFF", "0xFFFFFFFFFFFF");
  TestComparison ("0xFFFFFFFFFFFFFFFFFFFFFFFF", "1");

  TestMultiplication ("0", "0");
  TestMultiplication ("1", "0");
  TestMultiplication ("-1", "0");
  TestMultiplication ("1", "0x123456789ABCDEF");
  TestMultiplication ("-0x100000000", "-0x123456789ABCDEF");
  TestMultiplication ("0x123456789ABCDEF", "0");
  TestMultiplication ("0x123456789ABCDEF", "1");
  TestMultiplication ("0x123456789ABCDEF", "2");
  TestMultiplication ("12345678900", "100");
  TestMultiplication ("100", "12345678900");
  TestMultiplication ("123456789999", "-10000000000");
  TestMultiplication ("-10000000000", "123456789999");
  TestMultiplication ("123456789999", MinusInfinity);
  TestMultiplication (MinusInfinity, "123456789999");
  TestMultiplication (MinusInfinity, "+infinity");
  TestMultiplication ("0", MinusInfinity);
  TestMultiplication ("nan", "42");
  TestMultiplication ("12345678901234567890", "nAn");
  TestMultiplication ("-0x400000000", "16");

  TestSquaring ("0");
  TestSquaring ("1");
  TestSquaring ("-1");
  TestSquaring ("42");
  TestSquaring ("-1000000");
  TestSquaring ("-10000000000");
  TestSquaring (MinusInfinity);
  TestSquaring (NotANumber);

  printf ("\nThe end.\n");
}
