import static org.junit.Assert.*;

import java.math.BigInteger;

import org.junit.Test;

/**
 * Tests the constructors/methods of BigRational.
 * While more complete testing would be better, this is a good start.
 * Most of the tests do NOT use big numbers; use BigRationalTestFromCurt
 * for those tests.
 *
 * @author David Mutchler.  Created Mar 31, 2009.
 */
public class BigRationalTestFromDavid {

	/**
	 * Test method for {@link BigRational#BigRational(java.math.BigInteger, java.math.BigInteger)}.
	 */
	@Test
	public void testBigRationalBigIntegerBigInteger() {
		try {
			// Test 1: try to construct a BigRational whose denominator is zero.
			new BigRational(new BigInteger("7"), new BigInteger("0"));
			fail("Constructor did not throw ArithmeticException when denominator was zero");
		} catch (ArithmeticException exception) {
			// Test 1 succeeded if it gets here
		} catch (Exception exception) {
			exception.printStackTrace();
			fail("Constructor threw a " + exception.toString()
					+ " when it should have thrown an ArithmeticException");
		}

		try {
			// Test 2: construct a BigRational whose denominator is NOT zero.
			new BigRational(new BigInteger("0"), new BigInteger("7"));
		} catch (ArithmeticException exception) {
			fail("Constructor threw ArithmeticException when denominator was NOT zero");
		} catch (Exception exception) {
			exception.printStackTrace();
			fail("Constructor threw a " + exception.toString()
					+ " when it should not have thrown any Exception");
		}
		// Test 2 succeeded if it gets here
		
		try {
			// Test 3: try to construct a BigRational whose denominator is zero.
			new BigRational(new BigInteger("0"), new BigInteger("0"));
			fail("Constructor did not throw ArithmeticException when denominator was zero");
		} catch (ArithmeticException exception) {
			// Test 3 succeeded if it gets here
		} catch (Exception exception) {
			exception.printStackTrace();
			fail("Constructor threw a " + exception.toString()
					+ " when it should have thrown an ArithmeticException");
		}
	}

	/**
	 * Test method for {@link BigRational#BigRational(java.lang.String, java.lang.String)}.
	 */
	@Test
	public void testBigRationalStringString() {
		try {
			// Test 1: try to construct a BigRational whose denominator is zero.
			new BigRational("7777777777777777777777777777777777", "0");
			fail("Constructor did not throw ArithmeticException when denominator was zero");
		} catch (ArithmeticException exception) {
			// Test 1 succeeded if it gets here
		} catch (Exception exception) {
			exception.printStackTrace();
			fail("Constructor threw a " + exception.toString()
					+ " when it should have thrown an ArithmeticException");
		}

		try {
			// Test 2: construct a BigRational whose denominator is NOT zero.
			new BigRational("0", "7777777777777777777777777777777");
		} catch (ArithmeticException exception) {
			fail("Constructor threw ArithmeticException when denominator was NOT zero");
		} catch (Exception exception) {
			exception.printStackTrace();
			fail("Constructor threw a " + exception.toString()
					+ " when it should not have thrown any Exception");
		}
		// Test 2 succeeded if it gets here
		
		try {
			// Test 3: try to construct a BigRational whose denominator is zero.
			new BigRational(new BigInteger("0"), new BigInteger("000000000"));
			fail("Constructor did not throw ArithmeticException when denominator was zero");
		} catch (ArithmeticException exception) {
			// Test 3 succeeded if it gets here
		} catch (Exception exception) {
			exception.printStackTrace();
			fail("Constructor threw a " + exception.toString()
					+ " when it should have thrown an ArithmeticException");
		}
		
		try {
			// Test 4: try to construct a BigRational whose numerator is not an integer.
			new BigRational(new BigInteger("8.0"), new BigInteger("8"));
			fail("Constructor did not throw IllegalArgumentException when numerator is not an integer");
		} catch (IllegalArgumentException exception) {
			// Test 4 succeeded if it gets here
		} catch (Exception exception) {
			exception.printStackTrace();
			fail("Constructor threw a " + exception.toString()
					+ " when it should have thrown an IllegalArgumentException");
		}
		
		try {
			// Test 5: try to construct a BigRational whose denominator is not an integer.
			new BigRational(new BigInteger("8"), new BigInteger("bizarre"));
			fail("Constructor did not throw IllegalArgumentException when denominator is not an integer");
		} catch (IllegalArgumentException exception) {
			// Test 5 succeeded if it gets here
		} catch (Exception exception) {
			exception.printStackTrace();
			fail("Constructor threw a " + exception.toString()
					+ " when it should have thrown an IllegalArgumentException");
		}
		
		// Test 6: Should not generate any exceptions.
		new BigRational("88888888888888888888888888", "-44444444444444444444");
	}

	/**
	 * Test method for {@link BigRational#abs()}.
	 */
	@Test
	public void testAbs() {
		BigRational r = new BigRational("-2", "3");
		BigRational absR = new BigRational("2", "3");
		
		assertEquals(absR, r.abs());
		
		BigRational s = new BigRational("2", "-3");
		BigRational absS = new BigRational("2", "3");
		
		assertEquals(absS, s.abs());
		
		BigRational t = new BigRational("2", "3");
		BigRational absT = new BigRational("2", "3");
		
		assertEquals(absT, t.abs());
		
		BigRational u = new BigRational("-2", "-3");
		BigRational absU = new BigRational("2", "3");
		
		assertEquals(absU, u.abs());
		
		BigRational v = new BigRational("0", "-3");
		BigRational absV = new BigRational("0", "1");
		
		assertEquals(absV, v.abs());
	}

	/**
	 * Test method for {@link BigRational#add(BigRational)}.
	 */
	@Test
	public void testAdd() {
		BigRational r = new BigRational("2", "3");
		BigRational s = new BigRational("3", "4");
		BigRational sum = new BigRational("17", "12");
		BigRational zero = new BigRational("0", "1");
		
		assertEquals(sum, r.add(s));
		
		assertEquals(r, r.add(zero));
		assertEquals(r, zero.add(r));
		assertEquals(zero, zero.add(zero));
	}

	/**
	 * Test method for {@link BigRational#divide(BigRational)}.
	 */
	@Test
	public void testDivide() {
		BigRational r = new BigRational("-2", "3");
		BigRational s = new BigRational("3", "4");
		BigRational quotient = new BigRational("-8", "9");
		BigRational zero = new BigRational("0", "1");
		
		assertEquals(quotient, r.divide(s));
		
		assertEquals(zero, zero.divide(r));
		
		try {
			// Test division by zero; should throw an ArithmeticException
			r.divide(zero);
			fail("Did not throw ArithmeticException when attempted to divide by zero");
		} catch (ArithmeticException exception) {
			// Test for division by zero succeeded if it gets here
		} catch (Exception exception) {
			exception.printStackTrace();
			fail("Division by zero threw a " + exception.toString()
					+ " when it should have thrown an ArithmeticException");
		}
	}

	/**
	 * Test method for {@link BigRational#multiply(BigRational)}.
	 */
	@Test
	public void testMultiply() {
		BigRational r = new BigRational("-2", "3");
		BigRational s = new BigRational("3", "4");
		BigRational product = new BigRational("-1", "2");
		BigRational zero = new BigRational("0", "1");
		
		assertEquals(product, r.multiply(s));
		
		assertEquals(zero, r.multiply(new BigRational("0", "5")));
	}

	/**
	 * Test method for {@link BigRational#negate()}.
	 */
	@Test
	public void testNegate() {
		BigRational r = new BigRational("-2", "3");
		BigRational negR = new BigRational("2", "3");
		
		assertEquals(negR, r.negate());
		
		BigRational s = new BigRational("2", "-3");
		BigRational negS = new BigRational("2", "3");
		
		assertEquals(negS, s.negate());
		
		BigRational t = new BigRational("2", "3");
		BigRational negT = new BigRational("-2", "3");
		
		assertEquals(negT, t.negate());
		
		BigRational u = new BigRational("-2", "-3");
		BigRational negU = new BigRational("-2", "3");
		
		assertEquals(negU, u.negate());
		
		BigRational v = new BigRational("0", "3");
		BigRational negV = new BigRational("0", "1");
		
		assertEquals(negV, v.negate());
	}

	/**
	 * Test method for {@link BigRational#subtract(BigRational)}.
	 */
	@Test
	public void testSubtract() {
		BigRational r = new BigRational("2", "3");
		BigRational minusR = new BigRational("-2", "3");
		BigRational s = new BigRational("3", "4");
		BigRational difference = new BigRational("-1", "12");
		BigRational zero = new BigRational("0", "1");
		
		assertEquals(difference, r.subtract(s));
		
		assertEquals(r, r.subtract(zero));
		assertEquals(minusR, zero.subtract(r));
		assertEquals(zero, zero.subtract(zero));
		assertEquals(r, zero.subtract(minusR));
	}

	/**
	 * Test method for {@link BigRational#compareTo(BigRational)}.
	 */
	@Test
	public void testCompareTo() {
		BigRational r = new BigRational("3", "4");
	    BigRational s = new BigRational("2", "3");
	    
	    assertTrue(r.compareTo(s) > 0);
	    assertTrue(s.compareTo(r) < 0);
	    
	    assertTrue(r.compareTo(new BigRational("-15", "-20")) == 0);
	    
	    BigRational big = new BigRational("9999999999", "37");
	    BigRational bigger = new BigRational("88888888888", "36");
	    
	    assertTrue(big.compareTo(bigger) < 0);
	    assertTrue(bigger.compareTo(big) > 0);
	    assertTrue(bigger.compareTo(bigger) == 0);
	}

	/**
	 * Test method for {@link BigRational#equals(java.lang.Object)}.
	 */
	@Test
	public void testEqualsObject() {
		assertEquals(true, (new BigRational("3", "4")).equals(new BigRational("-9", "-12")));
		assertEquals(true, (new BigRational("33333333333333333333", "44444444444444444444")).equals(new BigRational("-9", "-12")));
		assertEquals(true, (new BigRational("0", "4")).equals(new BigRational("0", "3")));
		
		BigRational r = new BigRational("12345678901234567890", "23456789012345678901");
		assertEquals(true, r.equals(r));
		
		assertEquals(false, (new BigRational("1111111111", "1111111112")).equals(new BigRational("1111111110", "1111111112")));
		
		assertEquals(false, (new BigRational("1", "1")).equals(new Integer(1)));
	}

	/**
	 * Test method for {@link BigRational#toString()}.
	 */
	@Test
	public void testToString() {
		assertEquals("1 / 2", (new BigRational("2", "4")).toString());
		assertEquals("-1 / 2", (new BigRational("-2", "4")).toString());
		assertEquals("-1 / 2", (new BigRational("2", "-4")).toString());
		assertEquals("-4", (new BigRational("8", "-2")).toString());
		assertEquals("0", (new BigRational("000", "-2")).toString());
		
		assertEquals("1 / 2", (new BigRational(new BigInteger("2"), new BigInteger("4"))).toString());
		assertEquals("-1 / 2", (new BigRational(new BigInteger("-2"), new BigInteger("4"))).toString());
		assertEquals("-1 / 2", (new BigRational(new BigInteger("2"), new BigInteger("-4"))).toString());
		assertEquals("-4", (new BigRational(new BigInteger("8"), new BigInteger("-2"))).toString());
		assertEquals("0", (new BigRational(new BigInteger("000"), new BigInteger("-2"))).toString());
	}
}