/*
* File: RingTestHarness.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright August 1, 2006, Sandia Corporation. Under the terms of Contract
* DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
* or on behalf of the U.S. Government. Export of this program may require a
* license from the United States Government. See CopyrightHistory.txt for
* complete details.
*
*/
package gov.sandia.cognition.math;
import gov.sandia.cognition.util.ObjectUtil;
import java.util.Random;
import junit.framework.TestCase;
/**
* Abstract class that rigorously tests the methods in Ring using RANDOM
* subclasses.
* @param <RingType> Type of ring to test
* @author krdixon
*/
abstract public class RingTestHarness<RingType extends Ring<RingType>>
extends TestCase
{
/**
* Random-number generator to use
*/
public final Random RANDOM = new Random( 0 );
/**
* Range of the RANDOM numbers
*/
protected double RANGE = RANDOM.nextDouble() * 100.0;
/**
* Default tolerance
*/
protected static double TOLERANCE = 1e-5;
/**
* Constructor
* @param testName name of the test
*/
public RingTestHarness(
String testName )
{
super( testName );
}
/**
* Create a new random RingType object
* @return Random RingType
*/
abstract protected RingType createRandom();
/**
* Test of scaleEquals method, of class gov.sandia.isrc.math.Ring.
*/
abstract public void testScaleEquals();
/**
* Test of plusEquals method, of class gov.sandia.isrc.math.Ring.
*/
abstract public void testPlusEquals();
/**
* Test of dotTimesEquals method, of class gov.sandia.isrc.math.Ring.
*/
abstract public void testDotTimesEquals();
/**
* Test of equals method, of class gov.sandia.isrc.math.Ring.
*/
public void testEqualsRing()
{
System.out.println( "equals(Ring)" );
RingType r1 = this.createRandom();
assertFalse( r1.equals( null ) );
assertFalse( r1.equals( "False, please!" ) );
RingType r1clone = r1.clone();
assertEquals( r1, r1 );
assertEquals( r1, r1clone );
double delta = RANDOM.nextDouble() + 2.0;
RingType r2 = r1.scale( delta );
assertEquals( r1, r1clone );
assertFalse( r1.equals( r2 ) );
assertFalse( r1.equals( r2, TOLERANCE ) );
r1.zero();
r2.zero();
assertEquals( r1, r2 );
}
/**
* Test of clone method, of class gov.sandia.isrc.math.Ring.
*/
public void testClone()
{
System.out.println( "clone" );
RingType r1 = this.createRandom();
assertNotNull( r1 );
RingType r2 = r1.clone();
assertNotNull( r2 );
assertNotSame( r1, r2 );
assertEquals( r1, r2 );
r2.scaleEquals( RANDOM.nextDouble() );
assertFalse( r1.equals( r2 ) );
}
/**
* Tests the ability of the Ring to serialize itself.
*/
public void testSerialize() throws Exception
{
System.out.println( "serialize" );
RingType r1 = this.createRandom();
assertNotNull( r1 );
RingType r2 = ObjectUtil.deepCopy(r1);
assertNotNull( r2 );
assertNotSame( r1, r2 );
assertEquals( r1, r2 );
r2.scaleEquals( RANDOM.nextDouble() );
assertFalse( r1.equals( r2 ) );
}
/**
* Test of plus method, of class gov.sandia.isrc.math.Ring.
*/
public void testPlus()
{
System.out.println( "plus" );
// This test assumes that plusEquals has been tested and verified, and
// that the exception conditions are equivalent
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.scale( RANDOM.nextDouble() * 2.0 * RANGE - RANGE );
RingType r2clone = r2.clone();
// Check that plus() doesn't modify r1 or r2
r1.plus( r2 );
assertEquals( r1, r1clone );
assertEquals( r2, r2clone );
// Check that plusEquals() doesn't modify r2, but does modify r1
r1.plusEquals( r2 );
assertEquals( r2, r2clone );
assertFalse( r1.equals( r1clone ) );
// See if the plusEquals() result is the same as plus() result
assertEquals( r1, r1clone.plus( r2 ) );
// Self-addition should equal a scale of 2.0
assertEquals( r1.plus( r1 ), r1.scale( 2.0 ) );
try
{
r1.plus( null );
fail( "Should have thrown null-pointer exception: plus() " + r1.getClass() );
}
catch (NullPointerException e)
{
}
}
/**
* Test of minus method, of class gov.sandia.isrc.math.Ring.
*/
public void testMinus()
{
System.out.println( "minus" );
// This test assumes that plus and scale have been tested and verified
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.scale( RANDOM.nextDouble() * 2.0 * RANGE - RANGE );
RingType r2clone = r2.clone();
assertTrue( r1.minus( r2 ).equals( r1.plus( r2.scale( -1.0 ) ), TOLERANCE ) );
// This makes sure that the minus operator didn't modify the result
assertEquals( r1, r1clone );
assertEquals( r2, r2clone );
// Make sure minus and minusEquals return the same value
// and that the r2 doesn't get modified by the methods
r1.minusEquals( r2 );
assertEquals( r2clone, r2 );
assertEquals( r1, r1clone.minus( r2 ) );
assertEquals( r2clone, r2 );
// Self minus should equal zero-ing
r2.minusEquals( r2 );
r1.zero();
assertEquals( r1, r2 );
try
{
r1.minus( null );
fail( "Should have thrown null-pointer exception: minus() " + r1.getClass() );
}
catch (NullPointerException e)
{
}
}
/**
* Test of minusEquals method, of class gov.sandia.isrc.math.Ring.
*/
public void testMinusEquals()
{
System.out.println( "minusEquals" );
// This test assumes that plusEquals and scale have been tested and verified
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.scale( RANDOM.nextDouble() * 2.0 * RANGE - RANGE );
RingType r2clone = r2.clone();
r1.minusEquals( r2 );
assertEquals( r2, r2clone );
assertFalse( r1.equals( r1clone ) );
r1clone.plusEquals( r2.scale( -1.0 ) );
assertEquals( r2, r2clone );
assertTrue( r1.equals( r1clone, TOLERANCE ) );
try
{
r1.minusEquals( null );
fail( "Should have thrown null-pointer exception: minusEquals() " + r1.getClass() );
}
catch (NullPointerException e)
{
}
}
/**
* Test of dotTimes method, of class gov.sandia.isrc.math.Ring.
*/
public void testDotTimes()
{
System.out.println( "dotTimes" );
// This test assumes that dotTimesEquals has been tested and verified
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.scale( RANDOM.nextDouble() * 2.0 * RANGE - RANGE );
RingType r2clone = r2.clone();
r1.dotTimes( r2 );
assertEquals( r1, r1clone );
assertEquals( r2, r2clone );
r1.dotTimesEquals( r2 );
assertFalse( r1.equals( r1clone ) );
assertEquals( r2, r2clone );
assertTrue( r1.equals( r1clone.dotTimes( r2 ), TOLERANCE ) );
try
{
r1.dotTimes( null );
fail( "Should have thrown null-pointer exception: dotTimes() " + r1.getClass() );
}
catch (NullPointerException e)
{
}
}
/**
* Test of scale method, of class gov.sandia.isrc.math.Ring.
*/
public void testScale()
{
System.out.println( "scale" );
// This test assumes that scaleEquals has been tested and verified
double scaleFactor = RANDOM.nextDouble() * 2.0 * RANGE - RANGE;
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
assertEquals( r1, r1clone );
r1.scaleEquals( scaleFactor );
assertTrue( r1.equals( r1clone.scale( scaleFactor ), TOLERANCE ) );
assertFalse( r1.equals( r1clone ) );
assertEquals( r1.scale( 2.0 ), r1.plus( r1 ) );
}
/**
* Test of scaledPlus method.
*/
public void testScaledPlus()
{
System.out.println("scaledPlus");
// This test assumes that plusEquals has been tested and verified, and
// that the exception conditions are equivalent
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.scale(RANDOM.nextDouble() * 2.0 * RANGE - RANGE);
RingType r2clone = r2.clone();
// Check that scaledPlus() doesn't modify r1 or r2
double scaleFactor = RANDOM.nextDouble() * 2.0 * RANGE - RANGE;
r1.scaledPlus(scaleFactor, r2);
assertEquals(r1, r1clone);
assertEquals(r2, r2clone);
assertEquals(r1.scaledPlus(scaleFactor, r2), r1.plus(r2.scale(scaleFactor)));
// Check some self additions.
assertEquals(r1.scaledPlus(1.0, r1), r1.scale(2.0), TOLERANCE);
assertEquals(r1.scaledPlus(2.0, r1), r1.scale(3.0), TOLERANCE);
assertEquals(r1.scaledPlus(-2.0, r1), r1.scale(-1.0), TOLERANCE);
assertEquals(r1.scaledPlus(-4.0, r1), r1.scale(-3.0), TOLERANCE);
// Doing a -1 with self should result in zero.
assertEquals(r1.scaledPlus(-1.0, r1), r1.scale(0.0), TOLERANCE);
for (int i = 0; i < 10; i++)
{
scaleFactor = RANDOM.nextDouble() * 2.0 * RANGE - RANGE;
assertEquals(r1.scaledPlus(scaleFactor, r2),
r1.plus(r2.scale(scaleFactor)));
assertEquals(r2.scaledPlus(scaleFactor, r1),
r2.plus(r1.scale(scaleFactor)));
}
boolean exceptionThrown = false;
try
{
r1.scaledPlus(scaleFactor, null);
}
catch (NullPointerException e)
{
exceptionThrown = true;
}
finally
{
assertTrue(exceptionThrown);
}
}
/**
* Test of scaledPlusEquals method.
*/
public void testScaledPlusEquals()
{
System.out.println("scaledPlusEquals");
// This test assumes that scaledPlus has been tested and verified, and
// that the exception conditions are equivalent
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.scale(RANDOM.nextDouble() * 2.0 * RANGE - RANGE);
RingType r2clone = r2.clone();
// Check that scaledPlus() doesn't modify r1 or r2
double scaleFactor = RANDOM.nextDouble() * 2.0 * RANGE - RANGE;
// Check that plusEquals() doesn't modify r2, but does modify r1
r1.scaledPlusEquals(scaleFactor, r2);
assertEquals(r2, r2clone);
assertFalse(r1.equals(r1clone));
// See if the plusEquals() result is the same as plus() result
assertEquals(r1, r1clone.scaledPlus(scaleFactor, r2));
for (int i = 0; i < 10; i++)
{
r1 = r1clone.clone();
r2 = r2clone.clone();
scaleFactor = RANDOM.nextDouble() * 2.0 * RANGE - RANGE;
r1.scaledPlusEquals(scaleFactor, r2);
assertEquals(r1,
r1clone.plus(r2clone.scale(scaleFactor)));
assertEquals(r1, r1clone.scaledPlus(scaleFactor, r2clone));
}
boolean exceptionThrown = false;
try
{
r1.scaledPlusEquals(scaleFactor, null);
}
catch (NullPointerException e)
{
exceptionThrown = true;
}
finally
{
assertTrue(exceptionThrown);
}
}
/**
* Test of scaledMinus method.
*/
public void testScaledMinus()
{
System.out.println("scaledMinus");
// This test assumes that minusEquals and scaledPlus have been tested
// and verified, and that the exception conditions are equivalent
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.scale(RANDOM.nextDouble() * 2.0 * RANGE - RANGE);
RingType r2clone = r2.clone();
// Check that scaledMinus() doesn't modify r1 or r2
double scaleFactor = RANDOM.nextDouble() * 2.0 * RANGE - RANGE;
r1.scaledMinus(scaleFactor, r2);
assertEquals(r1, r1clone);
assertEquals(r2, r2clone);
// Check some self additions.
assertEquals(r1.scaledMinus(2.0, r1), r1.scale(-1.0), TOLERANCE);
assertEquals(r1.scaledMinus(4.0, r1), r1.scale(-3.0), TOLERANCE);
assertEquals(r1.scaledMinus(-2.0, r1), r1.scale(3.0), TOLERANCE);
assertEquals(r1.scaledMinus(-4.0, r1), r1.scale(5.0), TOLERANCE);
// Doing a -1 with self should result in zero.
assertEquals(r1.scaledMinus(1.0, r1), r1.scale(0.0), TOLERANCE);
for (int i = 0; i < 10; i++)
{
scaleFactor = RANDOM.nextDouble() * 2.0 * RANGE - RANGE;
assertEquals(r1.scaledMinus(scaleFactor, r2),
r1.minus(r2.scale(scaleFactor)));
assertEquals(r2.scaledMinus(scaleFactor, r1),
r2.minus(r1.scale(scaleFactor)));
assertEquals(
r1.scaledMinus(scaleFactor, r2),
r1.scaledPlus(-scaleFactor, r2));
assertEquals(
r1.scaledMinus(scaleFactor, r2),
r1.scaledPlus(scaleFactor, r2.negative()));
}
boolean exceptionThrown = false;
try
{
r1.scaledMinus(scaleFactor, null);
}
catch (NullPointerException e)
{
exceptionThrown = true;
}
finally
{
assertTrue(exceptionThrown);
}
}
/**
* Test of scaledMinusEquals method.
*/
public void testScaledMinusEquals()
{
System.out.println("scaledMinusEquals");
// This test assumes that minus, scale, and scaledMinus have been
// tested and verified, and that the exception conditions are equivalent
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.scale(RANDOM.nextDouble() * 2.0 * RANGE - RANGE);
RingType r2clone = r2.clone();
// Check that scaledPlus() doesn't modify r1 or r2
double scaleFactor = RANDOM.nextDouble() * 2.0 * RANGE - RANGE;
// Check that plusEquals() doesn't modify r2, but does modify r1
r1.scaledMinusEquals(scaleFactor, r2);
assertEquals(r2, r2clone);
assertFalse(r1.equals(r1clone));
// See if the plusEquals() result is the same as plus() result
assertEquals(r1, r1clone.scaledMinus(scaleFactor, r2));
for (int i = 0; i < 10; i++)
{
r1 = r1clone.clone();
r2 = r2clone.clone();
scaleFactor = RANDOM.nextDouble() * 2.0 * RANGE - RANGE;
r1.scaledMinusEquals(scaleFactor, r2);
assertEquals(r1, r1clone.minus(r2clone.scale(scaleFactor)));
assertEquals(r1, r1clone.scaledMinus(scaleFactor, r2clone));
assertEquals(r1, r1clone.scaledPlus(-scaleFactor, r2));
assertEquals(r1, r1clone.scaledPlus(scaleFactor, r2.negative()));
}
boolean exceptionThrown = false;
try
{
r1.scaledMinusEquals(scaleFactor, null);
}
catch (NullPointerException e)
{
exceptionThrown = true;
}
finally
{
assertTrue(exceptionThrown);
}
}
/**
* Test of negative method, of class gov.sandia.isrc.math.Ring.
*/
public void testNegative()
{
System.out.println( "negative" );
// This test assumes that scale() has been tested and verified
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
r1.negative();
assertEquals( r1, r1clone );
assertTrue( r1.negative().equals( r1.scale( -1.0 ), TOLERANCE ) );
}
/**
* Test of negativeEquals method, of class gov.sandia.isrc.math.Ring.
*/
public void testNegativeEquals()
{
System.out.println( "negativeEquals" );
// This test assumes that scaleEquals() has been tested and verified
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.clone();
RingType r2clone = r2.clone();
assertEquals( r1, r1clone );
r1.negativeEquals();
assertFalse( r1.equals( r1clone ) );
assertEquals( r2, r2clone );
r2.scaleEquals( -1.0 );
assertFalse( r2.equals( r2clone ) );
assertTrue( r1.equals( r2, TOLERANCE ) );
}
/**
* Test of zero method, of class gov.sandia.isrc.math.Ring.
*/
public void testZero()
{
System.out.println( "zero" );
RingType r1 = this.createRandom();
RingType r1clone = r1.clone();
RingType r2 = r1.clone();
RingType r2clone = r2.clone();
assertEquals( r1, r2 );
r1.zero();
assertFalse( r1.equals( r1clone ) );
assertEquals( r1, r2.scale( 0.0 ));
assertEquals( r2, r2clone );
}
public void testIsZero()
{
System.out.println( "zero" );
RingType zero = this.createRandom();
zero.zero();
assertTrue(zero.isZero());
assertTrue(zero.isZero(1.0));
assertTrue(this.createRandom().scale(0.0).isZero());
assertTrue(this.createRandom().scale(0.0).isZero(1.0));
assertFalse(this.createRandom().isZero());
}
/**
* Asserts that the two rings are equal within a given tolerance.
* Note that this method uses the equals method on the given objects, so
* it should only be used in cases where that method can be assumed to
* function properly. That is, it should not be used to test the
* equals method itself.
*
* @param <RingType>
* The ring type.
* @param expected
* The expected value.
* @param actual
* @param tolerance
*/
public static <RingType extends Ring<RingType>> void assertEquals(
final RingType expected,
final RingType actual,
final double tolerance)
{
if (expected == null)
{
assertNull(actual);
}
else
{
if (!expected.equals(actual, tolerance))
{
fail("Expected " + expected + " but was " + actual
+ " which is not within tolerance of " + tolerance);
}
}
}
}