//  Unit test for a subrange type template for C++
//
//  Copyright (c) 2005 Russel Winder
//
//  Distributed under the Boost Software License, Version 1.0.  See
//  http://www.boost.org/LICENSE_1_0.txt.

/**
 *  @file
 *
 *  A test program (using Boost.Test) for the <code>subrange</code> type.
 *
 *  <p>This is in serious need of extending with far more test cases.</p>
 *
 *  <p>Copyright (c) 2005  Russel Winder.</p>
 *
 *  @author Russel Winder
 *  @version 1.0
 *  @date 2005-01-06 09:05
 */

#include <boost/test/unit_test.hpp>

using boost::unit_test_framework::test_suite ;

#include "subrange.hpp"

enum Day { monday, tuesday, wednesday, thursday, friday, saturday, sunday } ;

typedef subrange::subrange<subrange::ordinal_range<Day, monday, friday> > Weekday ;

void createDefaultTestEnum() {
  Weekday a ;
  BOOST_CHECK(a == monday) ;
}

void assignTestEnum() {
  Weekday a (monday) ;
  Weekday b (tuesday) ;
  a = b ;
  BOOST_CHECK(a == b) ;
}

void equalsTestEnum() {
  Weekday a (monday) ;
  Weekday b (monday) ;
  BOOST_CHECK(a == b) ;
}

void notEqualsTestEnum() {
  Weekday a (monday) ;
  Weekday b (tuesday) ;
  BOOST_CHECK(a != b) ;
}

void lessThanTestEnum() {
  Weekday a (monday) ;
  Weekday b (tuesday) ;
  BOOST_CHECK(a < b) ;
  BOOST_CHECK(!(a >= b)) ;
}

void lessThanEqualToTestEnum() {
  Weekday a (monday) ;
  Weekday b (monday) ;
  BOOST_CHECK(a <= b) ;
  BOOST_CHECK(!(a > b)) ;
}

void greaterThanTestEnum() {
  Weekday a (monday) ;
  Weekday b (tuesday) ;
  BOOST_CHECK(b > a) ;
  BOOST_CHECK(!(b <= a)) ;
}

void greaterThanEqualToTestEnum() {
  Weekday a (monday) ;
  Weekday b (monday) ;
  BOOST_CHECK(a >= b) ;
  BOOST_CHECK(!(a < b)) ;
}


typedef subrange::subrange<subrange::ordinal_range<short, 1, 99> > SubIntException ;

void createDefaultTestIntException() {
  SubIntException a ;
  BOOST_CHECK(a == 1) ;
}

void preincrementTestIntException() {
  SubIntException a (9) ;
  ++a ;
  BOOST_CHECK(a == 10) ;
}

void postincrementTestIntException() {
  SubIntException a (9) ;
  a++ ;
  BOOST_CHECK(a == 10) ;
}

void predecrementTestIntException() {
  SubIntException a (9) ;
  --a ;
  BOOST_CHECK(a == 8) ;
}

void postdecrementTestIntException() {
  SubIntException a (9) ;
  a-- ;
  BOOST_CHECK(a == 8) ;
}

void assignLiteralTestIntException() {
  SubIntException a (9) ;
  a = 20 ;
  BOOST_CHECK(a == 20) ;
  BOOST_CHECK_THROW(a = 200, subrange::range_error) ;
  BOOST_CHECK_THROW(a = -5, subrange::range_error) ;
}

void assignTestIntException() {
  SubIntException a (9) ;
  SubIntException b (20) ;
  a = b ;
  BOOST_CHECK(a == b) ;
  BOOST_CHECK(a == 20) ;
}

void addAssignTestIntException() {
  SubIntException a (9) ;
  SubIntException b (20) ;
  a += b ;
  BOOST_CHECK(a == 29) ;
  a += 10 ;
  BOOST_CHECK(a == 39) ;
  a += -10 ;
  BOOST_CHECK(a == 29) ;
  BOOST_CHECK_THROW(a += 200, subrange::range_error) ;
}

void subtractAssignTestIntException() {
  SubIntException a (20) ;
  SubIntException b (9) ;
  a -= b ;
  BOOST_CHECK(a == 11) ;
  a -= 5 ;
  BOOST_CHECK(a == 6) ;
  a -= -5 ;
  BOOST_CHECK(a == 11) ;
  BOOST_CHECK_THROW(b -= a, subrange::range_error) ;
}

void multiplyAssignTestIntException() {
  SubIntException a (20) ;
  SubIntException b (3) ;
  a *= b ;
  BOOST_CHECK(a == 60) ;
  BOOST_CHECK_THROW(a *= b, subrange::range_error) ;
}

void divideAssignTestIntException() {
  SubIntException a (20) ;
  SubIntException b (3) ;
  a /= b ;
  BOOST_CHECK(a == 6) ;
}

void remainderAssignTestIntException() {
  SubIntException a (20) ;
  SubIntException b (3) ;
  a %= b ;
  BOOST_CHECK(a == 2) ;
}

void xorAssignTestIntException() {
  SubIntException a (0x12) ;
  SubIntException b (0x03) ;
  a ^= b ;
  BOOST_CHECK(a == 0x11) ;
}

void andAssignTestIntException() {
  SubIntException a (0x12) ;
  SubIntException b (0x03) ;
  a &= b ;
  BOOST_CHECK(a == 0x02) ;
}

void orAssignTestIntException() {
  SubIntException a (0x12) ;
  SubIntException b (0x03) ;
  a |= b ;
  BOOST_CHECK(a == 0x13) ;
}

void shiftLeftAssignTestIntException() {
  SubIntException a (0x12) ;
  a <<= 1 ;
  BOOST_CHECK(a == 0x24) ;
}

void shiftRightAssignTestIntException() {
  SubIntException a (0x12) ;
  a >>= 1 ;
  BOOST_CHECK(a == 0x09) ;
}

void addTestIntException() {
  SubIntException a (9) ;
  SubIntException b (20) ;
  a = a + b ;
  BOOST_CHECK(a == 29) ;
  a = a + 10 ;
  BOOST_CHECK(a == 39) ;
  a = a + -10 ;
  BOOST_CHECK(a == 29) ;
  a = 10 + a ;
  BOOST_CHECK(a == 39) ;
  a = -10 + a ;
  BOOST_CHECK(a == 29) ;
}

void subtractTestIntException() {
  SubIntException a (20) ;
  SubIntException b (9) ;
  a = a - b ;
  BOOST_CHECK(a == 11) ;
}

void multiplyTestIntException() {
  SubIntException a (20) ;
  SubIntException b (3) ;
  a = a * b ;
  BOOST_CHECK(a == 60) ;
}

void divideTestIntException() {
  SubIntException a (20) ;
  SubIntException b (3) ;
  a = a / b ;
  BOOST_CHECK(a == 6) ;
}

void remainderTestIntException() {
  SubIntException a (20) ;
  SubIntException b (3) ;
  a = a % b ;
  BOOST_CHECK(a == 2) ;
}

void xorTestIntException() {
  SubIntException a (0x12) ;
  SubIntException b (0x03) ;
  a = a ^ b ;
  BOOST_CHECK(a == 0x11) ;
}

void andTestIntException() {
  SubIntException a (0x12) ;
  SubIntException b (0x03) ;
  a = a & b ;
  BOOST_CHECK(a == 0x02) ;
}

void orTestIntException() {
  SubIntException a (0x12) ;
  SubIntException b (0x03) ;
  a = a | b ;
  BOOST_CHECK(a == 0x13) ;
}

void shiftLeftTestIntException() {
  SubIntException a (0x12) ;
  a = a << 1 ;
  BOOST_CHECK(a == 0x24) ;
  BOOST_CHECK_THROW( a = a << 3, subrange::range_error) ;
}

void shiftRightTestIntException() {
  SubIntException a (0x12) ;
  a = a >> 1 ;
  BOOST_CHECK(a == 0x09) ;
  BOOST_CHECK_THROW(a = a >> 5, subrange::range_error) ;
}

void equalsTestIntException() {
  SubIntException a (9) ;
  SubIntException b (9) ;
  BOOST_CHECK(a == b) ;
}

void notEqualsTestIntException() {
  SubIntException a (9) ;
  SubIntException b (8) ;
  BOOST_CHECK(a != b) ;
}

void lessThanTestIntException() {
  SubIntException a (8) ;
  SubIntException b (9) ;
  BOOST_CHECK(a < b) ;
  BOOST_CHECK(!(a >= b)) ;
}

void lessThanEqualToTestIntException() {
  SubIntException a (8) ;
  SubIntException b (8) ;
  BOOST_CHECK(a <= b) ;
  BOOST_CHECK(!(a > b)) ;
}

void greaterThanTestIntException() {
  SubIntException a (8) ;
  SubIntException b (9) ;
  BOOST_CHECK(b > a) ;
  BOOST_CHECK(!(b <= a)) ;
}

void greaterThanEqualToTestIntException() {
  SubIntException a (8) ;
  SubIntException b (8) ;
  BOOST_CHECK(a >= b) ;
  BOOST_CHECK(!(a < b)) ;
}

typedef subrange::subrange<subrange::ordinal_range<short, 1, 99>, subrange::modulo_arithmetic> SubIntModulo ;

void createDefaultTestIntModulo() {
  SubIntModulo a ;
  BOOST_CHECK(a == 1) ;
}

void preincrementTestIntModulo() {
  SubIntModulo a (9) ;
  ++a ;
  BOOST_CHECK(a == 10) ;
}

void postincrementTestIntModulo() {
  SubIntModulo a (9) ;
  a++ ;
  BOOST_CHECK(a == 10) ;
}

void predecrementTestIntModulo() {
  SubIntModulo a (9) ;
  --a ;
  BOOST_CHECK(a == 8) ;
}

void postdecrementTestIntModulo() {
  SubIntModulo a (9) ;
  a-- ;
  BOOST_CHECK(a == 8) ;
}

void assignLiteralTestIntModulo() {
  SubIntModulo a (9) ;
  a = 20 ;
  BOOST_CHECK(a == 20) ;
  a = 200 ;
  BOOST_CHECK(a == 4) ;
  a = -5 ;
  BOOST_CHECK(a == 93) ;
}

void assignTestIntModulo() {
  SubIntModulo a (9) ;
  SubIntModulo b (20) ;
  a = b ;
  BOOST_CHECK(a == b) ;
  BOOST_CHECK(a == 20) ;
}

void addAssignTestIntModulo() {
  SubIntModulo a (9) ;
  SubIntModulo b (20) ;
  a += b ;
  BOOST_CHECK(a == 29) ;
  a += 10 ;
  BOOST_CHECK(a == 39) ;
  a += -10 ;
  BOOST_CHECK(a == 29) ;
  a += 200 ;
  BOOST_CHECK(a == 33) ;
}

void subtractAssignTestIntModulo() {
  SubIntModulo a (20) ;
  SubIntModulo b (9) ;
  a -= b ;
  BOOST_CHECK(a == 11) ;
  a -= 5 ;
  BOOST_CHECK(a == 6) ;
  a -= -5 ;
  BOOST_CHECK(a == 11) ;
  b -= a ;
  BOOST_CHECK(b == 96) ;
}

void multiplyAssignTestIntModulo() {
  SubIntModulo a (20) ;
  SubIntModulo b (3) ;
  a *= b ;
  BOOST_CHECK(a == 60) ;
  a *= b ;
  BOOST_CHECK(a == 82) ;
}

void divideAssignTestIntModulo() {
  SubIntModulo a (20) ;
  SubIntModulo b (3) ;
  a /= b ;
  BOOST_CHECK(a == 6) ;
}

void remainderAssignTestIntModulo() {
  SubIntModulo a (20) ;
  SubIntModulo b (3) ;
  a %= b ;
  BOOST_CHECK(a == 2) ;
}

void xorAssignTestIntModulo() {
  SubIntModulo a (0x12) ;
  SubIntModulo b (0x03) ;
  a ^= b ;
  BOOST_CHECK(a == 0x11) ;
}

void andAssignTestIntModulo() {
  SubIntModulo a (0x12) ;
  SubIntModulo b (0x03) ;
  a &= b ;
  BOOST_CHECK(a == 0x02) ;
}

void orAssignTestIntModulo() {
  SubIntModulo a (0x12) ;
  SubIntModulo b (0x03) ;
  a |= b ;
  BOOST_CHECK(a == 0x13) ;
}

void shiftLeftAssignTestIntModulo() {
  SubIntModulo a (0x12) ;
  a <<= 1 ;
  BOOST_CHECK(a == 0x24) ;
}

void shiftRightAssignTestIntModulo() {
  SubIntModulo a (0x12) ;
  a >>= 1 ;
  BOOST_CHECK(a == 0x09) ;
}

void addTestIntModulo() {
  SubIntModulo a (9) ;
  SubIntModulo b (20) ;
  a = a + b ;
  BOOST_CHECK(a == 29) ;
  a = a + 10 ;
  BOOST_CHECK(a == 39) ;
  a = a + -10 ;
  BOOST_CHECK(a == 29) ;
  a = 10 + a ;
  BOOST_CHECK(a == 39) ;
  a = -10 + a ;
  BOOST_CHECK(a == 29) ;
}

void subtractTestIntModulo() {
  SubIntModulo a (20) ;
  SubIntModulo b (9) ;
  a = a - b ;
  BOOST_CHECK(a == 11) ;
}

void multiplyTestIntModulo() {
  SubIntModulo a (20) ;
  SubIntModulo b (3) ;
  a = a * b ;
  BOOST_CHECK(a == 60) ;
}

void divideTestIntModulo() {
  SubIntModulo a (20) ;
  SubIntModulo b (3) ;
  a = a / b ;
  BOOST_CHECK(a == 6) ;
}

void remainderTestIntModulo() {
  SubIntModulo a (20) ;
  SubIntModulo b (3) ;
  a = a % b ;
  BOOST_CHECK(a == 2) ;
}

void xorTestIntModulo() {
  SubIntModulo a (0x12) ;
  SubIntModulo b (0x03) ;
  a = a ^ b ;
  BOOST_CHECK(a == 0x11) ;
}

void andTestIntModulo() {
  SubIntModulo a (0x12) ;
  SubIntModulo b (0x03) ;
  a = a & b ;
  BOOST_CHECK(a == 0x02) ;
}

void orTestIntModulo() {
  SubIntModulo a (0x12) ;
  SubIntModulo b (0x03) ;
  a = a | b ;
  BOOST_CHECK(a == 0x13) ;
}

void shiftLeftTestIntModulo() {
  SubIntModulo a (0x12) ;
  a = a << 1 ;
  BOOST_CHECK(a == 0x24) ;
  a = a << 3 ;
  BOOST_CHECK(a == 92) ;
}

void shiftRightTestIntModulo() {
  SubIntModulo a (0x12) ;
  a = a >> 1 ;
  BOOST_CHECK(a == 0x09) ;
  a = a >> 5 ;
  BOOST_CHECK(a == 98) ;
}

void equalsTestIntModulo() {
  SubIntModulo a (9) ;
  SubIntModulo b (9) ;
  BOOST_CHECK(a == b) ;
}

void notEqualsTestIntModulo() {
  SubIntModulo a (9) ;
  SubIntModulo b (8) ;
  BOOST_CHECK(a != b) ;
}

void lessThanTestIntModulo() {
  SubIntModulo a (8) ;
  SubIntModulo b (9) ;
  BOOST_CHECK(a < b) ;
  BOOST_CHECK(!(a >= b)) ;
}

void lessThanEqualToTestIntModulo() {
  SubIntModulo a (8) ;
  SubIntModulo b (8) ;
  BOOST_CHECK(a <= b) ;
  BOOST_CHECK(!(a > b)) ;
}

void greaterThanTestIntModulo() {
  SubIntModulo a (8) ;
  SubIntModulo b (9) ;
  BOOST_CHECK(b > a) ;
  BOOST_CHECK(!(b <= a)) ;
}

void greaterThanEqualToTestIntModulo() {
  SubIntModulo a (8) ;
  SubIntModulo b (8) ;
  BOOST_CHECK(a >= b) ;
  BOOST_CHECK(!(a < b)) ;
}

typedef subrange::subrange<subrange::ordinal_range<short, 1, 99>, subrange::saturated_arithmetic> SubIntSaturated ;

void createDefaultTestIntSaturated() {
  SubIntSaturated a ;
  BOOST_CHECK(a == 1) ;
}

void preincrementTestIntSaturated() {
  SubIntSaturated a (9) ;
  ++a ;
  BOOST_CHECK(a == 10) ;
}

void postincrementTestIntSaturated() {
  SubIntSaturated a (9) ;
  a++ ;
  BOOST_CHECK(a == 10) ;
}

void predecrementTestIntSaturated() {
  SubIntSaturated a (9) ;
  --a ;
  BOOST_CHECK(a == 8) ;
}

void postdecrementTestIntSaturated() {
  SubIntSaturated a (9) ;
  a-- ;
  BOOST_CHECK(a == 8) ;
}

void assignLiteralTestIntSaturated() {
  SubIntSaturated a (9) ;
  a = 20 ;
  BOOST_CHECK(a == 20) ;
  a = 200 ;
  BOOST_CHECK(a == 99) ;
  a = -5 ;
  BOOST_CHECK(a == 1) ;
}

void assignTestIntSaturated() {
  SubIntSaturated a (9) ;
  SubIntSaturated b (20) ;
  a = b ;
  BOOST_CHECK(a == b) ;
  BOOST_CHECK(a == 20) ;
}

void addAssignTestIntSaturated() {
  SubIntSaturated a (9) ;
  SubIntSaturated b (20) ;
  a += b ;
  BOOST_CHECK(a == 29) ;
  a += 10 ;
  BOOST_CHECK(a == 39) ;
  a += -10 ;
  BOOST_CHECK(a == 29) ;
  a += 200 ;
  BOOST_CHECK(a == 99) ;
}

void subtractAssignTestIntSaturated() {
  SubIntSaturated a (20) ;
  SubIntSaturated b (9) ;
  a -= b ;
  BOOST_CHECK(a == 11) ;
  a -= 5 ;
  BOOST_CHECK(a == 6) ;
  a -= -5 ;
  BOOST_CHECK(a == 11) ;
  b -= a ;
  BOOST_CHECK(b == 1) ;
}

void multiplyAssignTestIntSaturated() {
  SubIntSaturated a (20) ;
  SubIntSaturated b (3) ;
  a *= b ;
  BOOST_CHECK(a == 60) ;
  a *= b ;
  BOOST_CHECK(a == 99) ;
}

void divideAssignTestIntSaturated() {
  SubIntSaturated a (20) ;
  SubIntSaturated b (3) ;
  a /= b ;
  BOOST_CHECK(a == 6) ;
}

void remainderAssignTestIntSaturated() {
  SubIntSaturated a (20) ;
  SubIntSaturated b (3) ;
  a %= b ;
  BOOST_CHECK(a == 2) ;
}

void xorAssignTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  SubIntSaturated b (0x03) ;
  a ^= b ;
  BOOST_CHECK(a == 0x11) ;
}

void andAssignTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  SubIntSaturated b (0x03) ;
  a &= b ;
  BOOST_CHECK(a == 0x02) ;
}

void orAssignTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  SubIntSaturated b (0x03) ;
  a |= b ;
  BOOST_CHECK(a == 0x13) ;
}

void shiftLeftAssignTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  a <<= 1 ;
  BOOST_CHECK(a == 0x24) ;
}

void shiftRightAssignTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  a >>= 1 ;
  BOOST_CHECK(a == 0x09) ;
}

void addTestIntSaturated() {
  SubIntSaturated a (9) ;
  SubIntSaturated b (20) ;
  a = a + b ;
  BOOST_CHECK(a == 29) ;
  a = a + 10 ;
  BOOST_CHECK(a == 39) ;
  a = a + -10 ;
  BOOST_CHECK(a == 29) ;
  a = 10 + a ;
  BOOST_CHECK(a == 39) ;
  a = -10 + a ;
  BOOST_CHECK(a == 29) ;
}

void subtractTestIntSaturated() {
  SubIntSaturated a (20) ;
  SubIntSaturated b (9) ;
  a = a - b ;
  BOOST_CHECK(a == 11) ;
}

void multiplyTestIntSaturated() {
  SubIntSaturated a (20) ;
  SubIntSaturated b (3) ;
  a = a * b ;
  BOOST_CHECK(a == 60) ;
}

void divideTestIntSaturated() {
  SubIntSaturated a (20) ;
  SubIntSaturated b (3) ;
  a = a / b ;
  BOOST_CHECK(a == 6) ;
}

void remainderTestIntSaturated() {
  SubIntSaturated a (20) ;
  SubIntSaturated b (3) ;
  a = a % b ;
  BOOST_CHECK(a == 2) ;
}

void xorTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  SubIntSaturated b (0x03) ;
  a = a ^ b ;
  BOOST_CHECK(a == 0x11) ;
}

void andTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  SubIntSaturated b (0x03) ;
  a = a & b ;
  BOOST_CHECK(a == 0x02) ;
}

void orTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  SubIntSaturated b (0x03) ;
  a = a | b ;
  BOOST_CHECK(a == 0x13) ;
}

void shiftLeftTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  a = a << 1 ;
  BOOST_CHECK(a == 0x24) ;
  a = a << 3 ;
  BOOST_CHECK(a == 99) ;
}

void shiftRightTestIntSaturated() {
  SubIntSaturated a (0x12) ;
  a = a >> 1 ;
  BOOST_CHECK(a == 0x09) ;
  a = a >> 5 ;
  BOOST_CHECK(a == 1) ;
}

void equalsTestIntSaturated() {
  SubIntSaturated a (9) ;
  SubIntSaturated b (9) ;
  BOOST_CHECK(a == b) ;
}

void notEqualsTestIntSaturated() {
  SubIntSaturated a (9) ;
  SubIntSaturated b (8) ;
  BOOST_CHECK(a != b) ;
}

void lessThanTestIntSaturated() {
  SubIntSaturated a (8) ;
  SubIntSaturated b (9) ;
  BOOST_CHECK(a < b) ;
  BOOST_CHECK(!(a >= b)) ;
}

void lessThanEqualToTestIntSaturated() {
  SubIntSaturated a (8) ;
  SubIntSaturated b (8) ;
  BOOST_CHECK(a <= b) ;
  BOOST_CHECK(!(a > b)) ;
}

void greaterThanTestIntSaturated() {
  SubIntSaturated a (8) ;
  SubIntSaturated b (9) ;
  BOOST_CHECK(b > a) ;
  BOOST_CHECK(!(b <= a)) ;
}

void greaterThanEqualToTestIntSaturated() {
  SubIntSaturated a (8) ;
  SubIntSaturated b (8) ;
  BOOST_CHECK(a >= b) ;
  BOOST_CHECK(!(a < b)) ;
}

typedef subrange::ordinal_range<short, 1, 99> RangeTraits ;
typedef subrange::subrange<RangeTraits, subrange::NaN_arithmetic> SubIntNaN ;

inline bool isNaN(const SubIntNaN & s) { return subrange::NaN_arithmetic<RangeTraits>::isNaN(s) ; }

void createDefaultTestIntNaN() {
  SubIntNaN a ;
  BOOST_CHECK(a == 1) ;
}

void preincrementTestIntNaN() {
  SubIntNaN a (9) ;
  ++a ;
  BOOST_CHECK(a == 10) ;
}

void postincrementTestIntNaN() {
  SubIntNaN a (9) ;
  a++ ;
  BOOST_CHECK(a == 10) ;
}

void predecrementTestIntNaN() {
  SubIntNaN a (9) ;
  --a ;
  BOOST_CHECK(a == 8) ;
}

void postdecrementTestIntNaN() {
  SubIntNaN a (9) ;
  a-- ;
  BOOST_CHECK(a == 8) ;
}

void assignLiteralTestIntNaN() {
  SubIntNaN a (9) ;
  a = 20 ;
  BOOST_CHECK(a == 20) ;
  a = 200 ;
  BOOST_CHECK(isNaN(a)) ;
  a = -5 ;
  BOOST_CHECK(isNaN(a)) ;
}

void assignTestIntNaN() {
  SubIntNaN a (9) ;
  SubIntNaN b (20) ;
  a = b ;
  BOOST_CHECK(a == b) ;
  BOOST_CHECK(a == 20) ;
}

void addAssignTestIntNaN() {
  SubIntNaN a (9) ;
  SubIntNaN b (20) ;
  a += b ;
  BOOST_CHECK(a == 29) ;
  a += 10 ;
  BOOST_CHECK(a == 39) ;
  a += -10 ;
  BOOST_CHECK(a == 29) ;
  a += 200 ;
  BOOST_CHECK(isNaN(a)) ;
}

void subtractAssignTestIntNaN() {
  SubIntNaN a (20) ;
  SubIntNaN b (9) ;
  a -= b ;
  BOOST_CHECK(a == 11) ;
  a -= 5 ;
  BOOST_CHECK(a == 6) ;
  a -= -5 ;
  BOOST_CHECK(a == 11) ;
  b -= a ;
  BOOST_CHECK(isNaN(b)) ;
}

void multiplyAssignTestIntNaN() {
  SubIntNaN a (20) ;
  SubIntNaN b (3) ;
  a *= b ;
  BOOST_CHECK(a == 60) ;
  a *= b ;
  BOOST_CHECK(isNaN(a)) ;
}

void divideAssignTestIntNaN() {
  SubIntNaN a (20) ;
  SubIntNaN b (3) ;
  a /= b ;
  BOOST_CHECK(a == 6) ;
}

void remainderAssignTestIntNaN() {
  SubIntNaN a (20) ;
  SubIntNaN b (3) ;
  a %= b ;
  BOOST_CHECK(a == 2) ;
}

void xorAssignTestIntNaN() {
  SubIntNaN a (0x12) ;
  SubIntNaN b (0x03) ;
  a ^= b ;
  BOOST_CHECK(a == 0x11) ;
}

void andAssignTestIntNaN() {
  SubIntNaN a (0x12) ;
  SubIntNaN b (0x03) ;
  a &= b ;
  BOOST_CHECK(a == 0x02) ;
}

void orAssignTestIntNaN() {
  SubIntNaN a (0x12) ;
  SubIntNaN b (0x03) ;
  a |= b ;
  BOOST_CHECK(a == 0x13) ;
}

void shiftLeftAssignTestIntNaN() {
  SubIntNaN a (0x12) ;
  a <<= 1 ;
  BOOST_CHECK(a == 0x24) ;
}

void shiftRightAssignTestIntNaN() {
  SubIntNaN a (0x12) ;
  a >>= 1 ;
  BOOST_CHECK(a == 0x09) ;
}

void addTestIntNaN() {
  SubIntNaN a (9) ;
  SubIntNaN b (20) ;
  a = a + b ;
  BOOST_CHECK(a == 29) ;
  a = a + 10 ;
  BOOST_CHECK(a == 39) ;
  a = a + -10 ;
  BOOST_CHECK(a == 29) ;
  a = 10 + a ;
  BOOST_CHECK(a == 39) ;
  a = -10 + a ;
  BOOST_CHECK(a == 29) ;
}

void subtractTestIntNaN() {
  SubIntNaN a (20) ;
  SubIntNaN b (9) ;
  a = a - b ;
  BOOST_CHECK(a == 11) ;
}

void multiplyTestIntNaN() {
  SubIntNaN a (20) ;
  SubIntNaN b (3) ;
  a = a * b ;
  BOOST_CHECK(a == 60) ;
}

void divideTestIntNaN() {
  SubIntNaN a (20) ;
  SubIntNaN b (3) ;
  a = a / b ;
  BOOST_CHECK(a == 6) ;
}

void remainderTestIntNaN() {
  SubIntNaN a (20) ;
  SubIntNaN b (3) ;
  a = a % b ;
  BOOST_CHECK(a == 2) ;
}

void xorTestIntNaN() {
  SubIntNaN a (0x12) ;
  SubIntNaN b (0x03) ;
  a = a ^ b ;
  BOOST_CHECK(a == 0x11) ;
}

void andTestIntNaN() {
  SubIntNaN a (0x12) ;
  SubIntNaN b (0x03) ;
  a = a & b ;
  BOOST_CHECK(a == 0x02) ;
}

void orTestIntNaN() {
  SubIntNaN a (0x12) ;
  SubIntNaN b (0x03) ;
  a = a | b ;
  BOOST_CHECK(a == 0x13) ;
}

void shiftLeftTestIntNaN() {
  SubIntNaN a (0x12) ;
  a = a << 1 ;
  BOOST_CHECK(a == 0x24) ;
  a = a << 3 ;
  BOOST_CHECK(isNaN(a)) ;
}

void shiftRightTestIntNaN() {
  SubIntNaN a (0x12) ;
  a = a >> 1 ;
  BOOST_CHECK(a == 0x09) ;
  a = a >> 5 ;
  BOOST_CHECK(isNaN(a)) ;
}

void equalsTestIntNaN() {
  SubIntNaN a (9) ;
  SubIntNaN b (9) ;
  BOOST_CHECK(a == b) ;
}

void notEqualsTestIntNaN() {
  SubIntNaN a (9) ;
  SubIntNaN b (8) ;
  BOOST_CHECK(a != b) ;
}

void lessThanTestIntNaN() {
  SubIntNaN a (8) ;
  SubIntNaN b (9) ;
  BOOST_CHECK(a < b) ;
  BOOST_CHECK(!(a >= b)) ;
}

void lessThanEqualToTestIntNaN() {
  SubIntNaN a (8) ;
  SubIntNaN b (8) ;
  BOOST_CHECK(a <= b) ;
  BOOST_CHECK(!(a > b)) ;
}

void greaterThanTestIntNaN() {
  SubIntNaN a (8) ;
  SubIntNaN b (9) ;
  BOOST_CHECK(b > a) ;
  BOOST_CHECK(!(b <= a)) ;
}

void greaterThanEqualToTestIntNaN() {
  SubIntNaN a (8) ;
  SubIntNaN b (8) ;
  BOOST_CHECK(a >= b) ;
  BOOST_CHECK(!(a < b)) ;
}

//  Can't use any templates for defining floating point range traits as C++ forbids template parameters
//  that are not of ordinal type so we haver to do that manually.
 
class float_range {
 public :
  typedef double value_type ;
  typedef subrange::range_error exception_type ;
  static double min () { return 1.0 ; }
  static double max () { return 99.0 ; }
} ;

typedef subrange::subrange<float_range> SubFloat ;

void createDefaultTestFloat() {
  SubFloat a ;
  BOOST_CHECK(a == 1.0) ;
}

void preincrementTestFloat() {
  SubFloat a (9.0) ;
  ++a ;
  BOOST_CHECK(a == 10.0) ;
}

void postincrementTestFloat() {
  SubFloat a (9.0) ;
  a++ ;
  BOOST_CHECK(a == 10.0) ;
}

void predecrementTestFloat() {
  SubFloat a (9.0) ;
  --a ;
  BOOST_CHECK(a == 8.0) ;
}

void postdecrementTestFloat() {
  SubFloat a (9.0) ;
  a-- ;
  BOOST_CHECK(a == 8.0) ;
}

void assignLiteralTestFloat() {
  SubFloat a (9.0) ;
  a = 20.0 ;
  BOOST_CHECK(a == 20.0) ;
  BOOST_CHECK_THROW(a = 200.0, subrange::range_error) ;
  BOOST_CHECK_THROW(a = -5.0, subrange::range_error) ;
}

void assignTestFloat() {
  SubFloat a (9.0) ;
  SubFloat b (20.0) ;
  a = b ;
  BOOST_CHECK(a == b) ;
  BOOST_CHECK(a == 20.0) ;
}

void addAssignTestFloat() {
  SubFloat a (9.0) ;
  SubFloat b (20.0) ;
  a += b ;
  BOOST_CHECK(a == 29.0) ;
  a += 10 ;
  BOOST_CHECK(a == 39.0) ;
  a += -10 ;
  BOOST_CHECK(a == 29.0) ;
  BOOST_CHECK_THROW(a += 200.0, subrange::range_error) ;
}

void subtractAssignTestFloat() {
  SubFloat a (20.0) ;
  SubFloat b (9.0) ;
  a -= b ;
  BOOST_CHECK(a == 11.0) ;
  a -= 5.0 ;
  BOOST_CHECK(a == 6.0) ;
  a -= -5.0 ;
  BOOST_CHECK(a == 11.0) ;
  BOOST_CHECK_THROW(b -= a, subrange::range_error) ;
}

void multiplyAssignTestFloat() {
  SubFloat a (20.0) ;
  SubFloat b (3.0) ;
  a *= b ;
  BOOST_CHECK(a == 60.0) ;
  BOOST_CHECK_THROW(a *= b, subrange::range_error) ;
}

void divideAssignTestFloat() {
  SubFloat a (20.0) ;
  SubFloat b (4.0) ;
  a /= b ;
  BOOST_CHECK(a == 5.0) ;
}

void addTestFloat() {
  SubFloat a (9.0) ;
  SubFloat b (20.0) ;
  a = a + b ;
  BOOST_CHECK(a == 29.0) ;
  a = a + 10.0 ;
  BOOST_CHECK(a == 39.0) ;
  a = a + -10.0 ;
  BOOST_CHECK(a == 29.0) ;
  a = 10.0 + a ;
  BOOST_CHECK(a == 39.0) ;
  a = -10.0 + a ;
  BOOST_CHECK(a == 29.0) ;
}

void subtractTestFloat() {
  SubFloat a (20.0) ;
  SubFloat b (9.0) ;
  a = a - b ;
  BOOST_CHECK(a == 11.0) ;
}

void multiplyTestFloat() {
  SubFloat a (20.0) ;
  SubFloat b (3.0) ;
  a = a * b ;
  BOOST_CHECK(a == 60.0) ;
}

void divideTestFloat() {
  SubFloat a (20.0) ;
  SubFloat b (4.0) ;
  a = a / b ;
  BOOST_CHECK(a == 5.0) ;
}

void equalsTestFloat() {
  SubFloat a (9.0) ;
  SubFloat b (9.0) ;
  BOOST_CHECK(a == b) ;
}

void notEqualsTestFloat() {
  SubFloat a (9.0) ;
  SubFloat b (8.0) ;
  BOOST_CHECK(a != b) ;
}

void lessThanTestFloat() {
  SubFloat a (8.0) ;
  SubFloat b (9.0) ;
  BOOST_CHECK(a < b) ;
  BOOST_CHECK(!(a >= b)) ;
}

void lessThanEqualToTestFloat() {
  SubFloat a (8.0) ;
  SubFloat b (8.0) ;
  BOOST_CHECK(a <= b) ;
  BOOST_CHECK(!(a > b)) ;
}

void greaterThanTestFloat() {
  SubFloat a (8.0) ;
  SubFloat b (9.0) ;
  BOOST_CHECK(b > a) ;
  BOOST_CHECK(!(b <= a)) ;
}

void greaterThanEqualToTestFloat() {
  SubFloat a (8.0) ;
  SubFloat b (8.0) ;
  BOOST_CHECK(a >= b) ;
  BOOST_CHECK(!(a < b)) ;
}

test_suite * init_unit_test_suite(const int argc, char * *const argv) {
  test_suite *const test = BOOST_TEST_SUITE( "Subrange test using Boost.Test." ) ;
  test->add(BOOST_TEST_CASE(createDefaultTestEnum)) ;
  test->add(BOOST_TEST_CASE(assignTestEnum)) ;
  test->add(BOOST_TEST_CASE(equalsTestEnum)) ;
  test->add(BOOST_TEST_CASE(notEqualsTestEnum)) ;
  test->add(BOOST_TEST_CASE(lessThanTestEnum)) ;
  test->add(BOOST_TEST_CASE(lessThanEqualToTestEnum)) ;
  test->add(BOOST_TEST_CASE(greaterThanTestEnum)) ;
  test->add(BOOST_TEST_CASE(greaterThanEqualToTestEnum)) ;

  test->add(BOOST_TEST_CASE(createDefaultTestIntException)) ;
  test->add(BOOST_TEST_CASE(preincrementTestIntException)) ;
  test->add(BOOST_TEST_CASE(postincrementTestIntException)) ;
  test->add(BOOST_TEST_CASE(predecrementTestIntException)) ;
  test->add(BOOST_TEST_CASE(postdecrementTestIntException)) ;
  test->add(BOOST_TEST_CASE(assignLiteralTestIntException)) ;
  test->add(BOOST_TEST_CASE(assignTestIntException)) ;
  test->add(BOOST_TEST_CASE(addAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(subtractAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(multiplyAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(divideAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(remainderAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(xorAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(andAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(orAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(shiftLeftAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(shiftRightAssignTestIntException)) ;
  test->add(BOOST_TEST_CASE(addTestIntException)) ;
  test->add(BOOST_TEST_CASE(subtractTestIntException)) ;
  test->add(BOOST_TEST_CASE(multiplyTestIntException)) ;
  test->add(BOOST_TEST_CASE(divideTestIntException)) ;
  test->add(BOOST_TEST_CASE(remainderTestIntException)) ;
  test->add(BOOST_TEST_CASE(xorTestIntException)) ;
  test->add(BOOST_TEST_CASE(andTestIntException)) ;
  test->add(BOOST_TEST_CASE(orTestIntException)) ;
  test->add(BOOST_TEST_CASE(shiftLeftTestIntException)) ;
  test->add(BOOST_TEST_CASE(shiftRightTestIntException)) ;
  test->add(BOOST_TEST_CASE(equalsTestIntException)) ;
  test->add(BOOST_TEST_CASE(notEqualsTestIntException)) ;
  test->add(BOOST_TEST_CASE(lessThanTestIntException)) ;
  test->add(BOOST_TEST_CASE(lessThanEqualToTestIntException)) ;
  test->add(BOOST_TEST_CASE(greaterThanTestIntException)) ;
  test->add(BOOST_TEST_CASE(greaterThanEqualToTestIntException)) ;

  test->add(BOOST_TEST_CASE(createDefaultTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(preincrementTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(postincrementTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(predecrementTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(postdecrementTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(assignLiteralTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(assignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(addAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(subtractAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(multiplyAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(divideAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(remainderAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(xorAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(andAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(orAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(shiftLeftAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(shiftRightAssignTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(addTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(subtractTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(multiplyTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(divideTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(remainderTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(xorTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(andTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(orTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(shiftLeftTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(shiftRightTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(equalsTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(notEqualsTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(lessThanTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(lessThanEqualToTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(greaterThanTestIntModulo)) ;
  test->add(BOOST_TEST_CASE(greaterThanEqualToTestIntModulo)) ;

  test->add(BOOST_TEST_CASE(createDefaultTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(preincrementTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(postincrementTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(predecrementTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(postdecrementTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(assignLiteralTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(assignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(addAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(subtractAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(multiplyAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(divideAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(remainderAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(xorAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(andAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(orAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(shiftLeftAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(shiftRightAssignTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(addTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(subtractTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(multiplyTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(divideTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(remainderTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(xorTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(andTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(orTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(shiftLeftTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(shiftRightTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(equalsTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(notEqualsTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(lessThanTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(lessThanEqualToTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(greaterThanTestIntSaturated)) ;
  test->add(BOOST_TEST_CASE(greaterThanEqualToTestIntSaturated)) ;

  test->add(BOOST_TEST_CASE(createDefaultTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(preincrementTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(postincrementTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(predecrementTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(postdecrementTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(assignLiteralTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(assignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(addAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(subtractAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(multiplyAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(divideAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(remainderAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(xorAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(andAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(orAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(shiftLeftAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(shiftRightAssignTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(addTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(subtractTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(multiplyTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(divideTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(remainderTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(xorTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(andTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(orTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(shiftLeftTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(shiftRightTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(equalsTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(notEqualsTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(lessThanTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(lessThanEqualToTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(greaterThanTestIntNaN)) ;
  test->add(BOOST_TEST_CASE(greaterThanEqualToTestIntNaN)) ;

  test->add(BOOST_TEST_CASE(createDefaultTestFloat)) ;
  test->add(BOOST_TEST_CASE(preincrementTestFloat)) ;
  test->add(BOOST_TEST_CASE(postincrementTestFloat)) ;
  test->add(BOOST_TEST_CASE(predecrementTestFloat)) ;
  test->add(BOOST_TEST_CASE(postdecrementTestFloat)) ;
  test->add(BOOST_TEST_CASE(assignLiteralTestFloat)) ;
  test->add(BOOST_TEST_CASE(assignTestFloat)) ;
  test->add(BOOST_TEST_CASE(addAssignTestFloat)) ;
  test->add(BOOST_TEST_CASE(subtractAssignTestFloat)) ;
  test->add(BOOST_TEST_CASE(multiplyAssignTestFloat)) ;
  test->add(BOOST_TEST_CASE(divideAssignTestFloat)) ;
  test->add(BOOST_TEST_CASE(addTestFloat)) ;
  test->add(BOOST_TEST_CASE(subtractTestFloat)) ;
  test->add(BOOST_TEST_CASE(multiplyTestFloat)) ;
  test->add(BOOST_TEST_CASE(divideTestFloat)) ;
  test->add(BOOST_TEST_CASE(equalsTestFloat)) ;
  test->add(BOOST_TEST_CASE(notEqualsTestFloat)) ;
  test->add(BOOST_TEST_CASE(lessThanTestFloat)) ;
  test->add(BOOST_TEST_CASE(lessThanEqualToTestFloat)) ;
  test->add(BOOST_TEST_CASE(greaterThanTestFloat)) ;
  test->add(BOOST_TEST_CASE(greaterThanEqualToTestFloat)) ;

  return test ;
}
