/*********************************************************
** Copyright (c) 2005
** University of Washington
** Licensed under the terms set forth by University of
** Washington. If you did not sign such a license, you
** are using this software/code illegally and you do not
** have permission to use, modify, or redistribute
** this or any files in this software package.
**
** File: SafeIntTest.h
**
**********************************************************/
#ifndef __SAFEINTTEST__
#define __SAFEINTTEST__

#include "SafeInt.h"
#include <stdexcept>
using namespace std;

class CSafeIntTest : public CUnitTestClass
{
 public:
  CSafeIntTest() : CUnitTestClass("SafeIntTest")
  {
  }

 protected:
  void RunTests()
  {
    TestCSafeInt();
  }

 private:
#define ExpectOutOfRange(EXPR) \
  try {								 \
    do { EXPR; } while(0);					 \
    __throw_message("Expected out_of_range exception"); \
  } catch(out_of_range* pOr) \
  { \
    delete pOr; \
    } 
 
  void TestCSafeInt()
  {
    BeginTest("TestCSafeInt");
    bool success = true;
    uintmax_t i,j;
    try
    {
      ExpectOutOfRange(CSafeInt<uintmax_t>::Add(UINTMAX_MAX, UINTMAX_MAX));
      ExpectOutOfRange(CSafeInt<uintmax_t>::Add(UINTMAX_MAX, 1));
      __test_assert_nomsg(CSafeInt<uintmax_t>::Add(UINTMAX_MAX - 1, 1) == UINTMAX_MAX);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Add(23, 42) == 65);

      ExpectOutOfRange(CSafeInt<uintmax_t>::Subtract(1, UINTMAX_MAX));
      ExpectOutOfRange(CSafeInt<uintmax_t>::Subtract(0, 1));
      ExpectOutOfRange(CSafeInt<uintmax_t>::Subtract(UINTMAX_MAX-1, UINTMAX_MAX));
      __test_assert_nomsg(CSafeInt<uintmax_t>::Subtract(UINTMAX_MAX, UINTMAX_MAX) == 0);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Subtract(1, 0) == 1);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Subtract(42, 23) == 19);

      ExpectOutOfRange(CSafeInt<uintmax_t>::Multiply(2, UINTMAX_MAX));
      ExpectOutOfRange(CSafeInt<uintmax_t>::Multiply(UINTMAX_MAX-1, UINTMAX_MAX));
      __test_assert_nomsg(CSafeInt<uintmax_t>::Multiply(1, UINTMAX_MAX) == UINTMAX_MAX);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Multiply(1, 0) == 0);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Multiply(42, 23) == 966);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Multiply(42, 0) == 0);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Multiply(0, 42) == 0);

      ExpectOutOfRange(CSafeInt<uintmax_t>::Divide(1, 0));
      ExpectOutOfRange(CSafeInt<uintmax_t>::Divide(UINTMAX_MAX, 0));
      __test_assert_nomsg(CSafeInt<uintmax_t>::Divide(0, UINTMAX_MAX) == 0);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Divide(0, 1) == 0);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Divide(42, 23) == 1);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Divide(42, 6) == 7);

      ExpectOutOfRange(CSafeInt<uintmax_t>::Mod(1, 0));
      ExpectOutOfRange(CSafeInt<uintmax_t>::Mod(UINTMAX_MAX, 0));
      __test_assert_nomsg(CSafeInt<uintmax_t>::Mod(0, UINTMAX_MAX) == 0);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Mod(0, 1) == 0);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Mod(42, 23) == 19);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Mod(42, 6) == 0);
      __test_assert_nomsg(CSafeInt<uintmax_t>::Mod(42, 5) == 2);
    }
    catch(CTestException* pEx)
    {
      success = false;
      cout << pEx->Message() << "\n";
      delete pEx;
    }
    catch(out_of_range *pOr)
    {
      success = false;
      cout << "Got out_of_range when not expecting one\n";
      delete pOr;
    }
    catch(...)
    {
      success = false;
      cout << "caught unknown exception.\n";
    }

    EndTest(success);
  }

};

#endif
