package net.sf.openrocket.rocketcomponent;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.BitSet;
import java.util.EventObject;
import java.util.Iterator;
import net.sf.openrocket.rocketcomponent.RocketComponent.Position;
import net.sf.openrocket.util.StateChangeListener;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import org.junit.Test;
public class ConfigurationTest extends BaseTestCase {
/**
* Test change events and modIDs
*/
@Test
public void testChangeEvent() {
/* Setup */
Rocket r1 = makeEmptyRocket();
Configuration config = r1.getDefaultConfiguration();
StateChangeListener listener1 = new StateChangeListener() {
@Override
public void stateChanged(EventObject e) {
}
};
StateChangeListener listener2 = new StateChangeListener() {
@Override
public void stateChanged(EventObject e) {
}
};
config.addChangeListener(listener1);
config.addChangeListener(listener2);
/* Test */
// ModID should not change if nothing changed
int origModID = config.getModID();
int noChangeModID = config.getModID();
assertTrue(origModID == noChangeModID);
// After a change event, modID should change
config.fireChangeEvent();
int changeModID = config.getModID();
assertTrue(origModID < changeModID);
/* Cleanup */
config.removeChangeListener(listener1);
config.removeChangeListener(listener2);
config.release();
}
/**
* Test configuration rocket component and motor iterators
*/
@Test
public void testConfigIterators() {
/* Setup */
Rocket r1 = makeSingleStageTestRocket();
Configuration config = r1.getDefaultConfiguration();
/* Test */
// Test rocket component iterator
// TODO: validate iterator iterates correctly
for (Iterator<RocketComponent> i = config.iterator(); i.hasNext();) {
i.next();
}
// Rocket component iterator remove method is unsupported, should throw exception
try {
Iterator<RocketComponent> configIterator = config.iterator();
configIterator.remove();
} catch (UnsupportedOperationException e) {
assertTrue(e.getMessage().equals("remove unsupported"));
}
// Test motor iterator
/* TODO: no motors in model Iterator<MotorMount> motorIterator()
* TODO: validate iterator iterates correctly
for (Iterator<MotorMount> i = config.motorIterator(); i.hasNext();) {
i.next();
}
*/
// Motor iterator remove method is unsupported, should throw exception
try {
Iterator<MotorMount> motorIterator = config.motorIterator();
motorIterator.remove();
} catch (UnsupportedOperationException e) {
assertTrue(e.getMessage().equals("remove unsupported"));
}
/* Cleanup */
config.release();
}
/**
* Empty rocket (no components) specific configuration tests
*/
@Test
public void testEmptyRocket() {
Rocket r1 = makeEmptyRocket();
Configuration config = r1.getDefaultConfiguration();
Configuration configClone = config.clone(); // TODO validate clone worked
assertFalse(config.getRocket() == null);
assertFalse(config.hasMotors());
config.release();
}
/**
* Test flight configuration ID methods
*/
@Test
public void testFlightConfigID() {
/* Setup */
Rocket r1 = makeSingleStageTestRocket();
Configuration config = r1.getDefaultConfiguration();
/* Test */
// Test flight configuration ID setting
String origFlightConfigID = config.getFlightConfigurationID(); // save for later
String testFlightConfigID = origFlightConfigID + "_ConfigurationTest";
// if id is already set (ie, not null), setting to null should work
assertFalse(config.getFlightConfigurationID() == null);
config.setFlightConfigurationID(null);
assertTrue(config.getFlightConfigurationID() == null);
// now that id is set to null, setting to null should not set again (do for coverage)
config.setFlightConfigurationID(null);
assertTrue(config.getFlightConfigurationID() == null);
// reset the id from null to a test value
config.setFlightConfigurationID(testFlightConfigID);
assertTrue(config.getFlightConfigurationID().equals(testFlightConfigID));
// setting it to the same non-null value should just return (do for coverage)
config.setFlightConfigurationID(testFlightConfigID);
assertTrue(config.getFlightConfigurationID().equals(testFlightConfigID));
// set back to original value
config.setFlightConfigurationID(origFlightConfigID);
assertTrue(config.getFlightConfigurationID().equals(origFlightConfigID));
/* Cleanup */
config.release();
}
/**
* Test flight configuration ID methods
*/
@Test
public void testGeneralMethods() {
/* Setup */
Rocket r1 = makeSingleStageTestRocket();
Configuration config = r1.getDefaultConfiguration();
/* Test */
// general method tests
Configuration configClone = config.clone(); // TODO validate clone worked
assertFalse(config.getRocket() == null);
// TODO rocket has no motors! assertTrue(config.hasMotors());
// rocket info tests
double length = config.getLength();
double refLength = config.getReferenceLength();
double refArea = config.getReferenceArea();
// TODO validate that the values are correct
//log.debug("ConfigurationTest, length: " + String.valueOf(length));
//log.debug("ConfigurationTest, refLength: " + String.valueOf(refLength));
//log.debug("ConfigurationTest, refArea: " + String.valueOf(refArea));
/* Cleanup */
config.release();
}
/**
* Single stage rocket specific configuration tests
*/
@Test
public void testSingleStageRocket() {
/* Setup */
Rocket r1 = makeSingleStageTestRocket();
Configuration config = r1.getDefaultConfiguration();
BitSet activeStageFlags = new BitSet();
activeStageFlags.set(0, false); // first stage
/* Test */
// test cloning of single stage rocket
Configuration configClone = config.clone(); // TODO validate clone worked
// test explicitly setting only first stage active
config.setOnlyStage(0);
activeStageFlags.clear();
activeStageFlags.set(0, true);
validateStages(config, 1, activeStageFlags);
// test explicitly setting all stages up to first stage active
config.setToStage(0);
activeStageFlags.clear();
activeStageFlags.set(0, true);
validateStages(config, 1, activeStageFlags);
// test explicitly setting all stages active
config.setAllStages();
activeStageFlags.clear();
activeStageFlags.set(0, true);
validateStages(config, 1, activeStageFlags);
// Cleanup
config.release();
}
/**
* Multi stage rocket specific configuration tests
*/
@Test
public void testMultiStageRocket() {
/* Setup */
Rocket r1 = makeTwoStageTestRocket();
Configuration config = r1.getDefaultConfiguration();
BitSet activeStageFlags = new BitSet();
activeStageFlags.set(0, false); // booster (first) stage
activeStageFlags.set(1, false); // sustainer (second) stage
/* Test */
// test cloning of two stage rocket
Configuration configClone = config.clone(); // TODO validate clone worked
// test explicitly setting only first stage active
config.setOnlyStage(0);
activeStageFlags.clear();
activeStageFlags.set(0, true);
validateStages(config, 2, activeStageFlags);
// test explicitly setting all stages up to first stage active
config.setToStage(0);
activeStageFlags.clear();
activeStageFlags.set(0, true);
validateStages(config, 2, activeStageFlags);
// test explicitly setting all stages up to second stage active
config.setToStage(1);
activeStageFlags.clear();
activeStageFlags.set(0, 2, true);
validateStages(config, 2, activeStageFlags);
// test explicitly setting all two stages active
config.setAllStages();
activeStageFlags.clear();
activeStageFlags.set(0, 2, true);
validateStages(config, 2, activeStageFlags);
// Cleanup
config.release();
}
///////////////////// Helper Methods ////////////////////////////
public void validateStages(Configuration config, int expectedStageCount, BitSet activeStageFlags) {
// test that getStageCount() returns correct value
int stageCount = config.getStageCount();
assertTrue(stageCount == expectedStageCount);
// test that getActiveStageCount() and getActiveStages() returns correct values
int expectedActiveStageCount = 0;
for (int i = 0; i < expectedStageCount; i++) {
if (activeStageFlags.get(i)) {
expectedActiveStageCount++;
}
}
assertTrue(config.getActiveStageCount() == expectedActiveStageCount);
int[] stages = config.getActiveStages();
assertTrue(stages.length == expectedActiveStageCount);
// test if isHead() detects first stage being active or inactive
if (activeStageFlags.get(0)) {
assertTrue(config.isHead());
} else {
assertFalse(config.isHead());
}
// test if isStageActive() detects stage x being active or inactive
for (int i = 0; i < expectedStageCount; i++) {
if (activeStageFlags.get(i)) {
assertTrue(config.isStageActive(i));
} else {
assertFalse(config.isStageActive(i));
}
}
// test boundary conditions
// stage -1 should not exist, and isStageActive() should throw exception
boolean IndexOutOfBoundsExceptionFlag = false;
try {
assertFalse(config.isStageActive(-1));
} catch (IndexOutOfBoundsException e) {
IndexOutOfBoundsExceptionFlag = true;
}
assertTrue(IndexOutOfBoundsExceptionFlag);
// n+1 stage should not exist, isStageActive() should return false
// TODO: isStageActive(stageCount + 1) really should throw IndexOutOfBoundsException
assertFalse(config.isStageActive(stageCount + 1));
}
//////////////////// Test Rocket Creation Methods /////////////////////////
public static Rocket makeEmptyRocket() {
Rocket rocket = new Rocket();
return rocket;
}
public static Rocket makeSingleStageTestRocket() {
// TODO: get units correct, these units are prob wrong, are lengths are CM, mass are grams
Rocket rocket;
Stage stage;
NoseCone nosecone;
BodyTube tube1;
TrapezoidFinSet finset;
// body tube constants
final double R = 2.5 / 2; // cm
final double BT_T = 0.1;
// nose cone constants
final double NC_T = 0.2;
final double R2 = 2.3 / 2;
rocket = new Rocket();
stage = new Stage();
stage.setName("Stage1");
nosecone = new NoseCone(Transition.Shape.OGIVE, 10.0, R);
nosecone.setThickness(NC_T);
nosecone.setAftShoulderLength(2.0);
nosecone.setAftShoulderRadius(R2);
nosecone.setAftShoulderThickness(NC_T);
nosecone.setAftShoulderCapped(true);
nosecone.setFilled(false);
stage.addChild(nosecone);
tube1 = new BodyTube(30, R, BT_T);
stage.addChild(tube1);
LaunchLug lug = new LaunchLug();
lug.setLength(3.5);
tube1.addChild(lug);
/*
TubeCoupler coupler = new TubeCoupler();
coupler.setOuterRadiusAutomatic(true);
coupler.setThickness(0.005);
coupler.setLength(0.28);
coupler.setMassOverridden(true);
coupler.setOverrideMass(0.360);
coupler.setRelativePosition(Position.BOTTOM);
coupler.setPositionValue(-0.14);
tube1.addChild(coupler);
*/
// Parachute
MassComponent mass = new MassComponent(4.5, R2, 8.0);
mass.setRelativePosition(Position.TOP);
mass.setPositionValue(3.0);
tube1.addChild(mass);
// Cord
mass = new MassComponent(40.0, R2, 72);
mass.setRelativePosition(Position.TOP);
mass.setPositionValue(2.0);
tube1.addChild(mass);
// Motor mount
InnerTube inner = new InnerTube();
inner.setMotorMount(true);
inner.setPositionValue(0.5);
inner.setRelativePosition(Position.BOTTOM);
inner.setOuterRadius(1.9 / 2);
inner.setInnerRadius(1.8 / 2);
inner.setLength(7.5);
tube1.addChild(inner);
// Centering rings for motor mount
CenteringRing center = new CenteringRing();
center.setInnerRadiusAutomatic(true);
center.setOuterRadiusAutomatic(true);
center.setLength(0.005);
center.setMassOverridden(true);
center.setOverrideMass(0.038);
center.setRelativePosition(Position.BOTTOM);
center.setPositionValue(0.25);
tube1.addChild(center);
center = new CenteringRing();
center.setInnerRadiusAutomatic(true);
center.setOuterRadiusAutomatic(true);
center.setLength(0.005);
center.setMassOverridden(true);
center.setOverrideMass(0.038);
center.setRelativePosition(Position.BOTTOM);
center.setPositionValue(-6.0);
tube1.addChild(center);
center = new CenteringRing();
center.setInnerRadiusAutomatic(true);
center.setOuterRadiusAutomatic(true);
center.setLength(0.005);
center.setMassOverridden(true);
center.setOverrideMass(0.038);
center.setRelativePosition(Position.TOP);
center.setPositionValue(0.83);
tube1.addChild(center);
// Fins
finset = new TrapezoidFinSet();
finset.setFinCount(3);
finset.setRootChord(5.0);
finset.setTipChord(5.0);
finset.setHeight(3.0);
finset.setThickness(0.005);
finset.setSweepAngle(40.0);
finset.setRelativePosition(Position.BOTTOM);
finset.setPositionValue(-0.5);
finset.setBaseRotation(Math.PI / 2);
tube1.addChild(finset);
// Stage construction
rocket.addChild(stage);
rocket.setPerfectFinish(false);
// Flight configuration
String id = rocket.newFlightConfigurationID();
// Motor m = Application.getMotorSetDatabase().findMotors(null, null, "L540", Double.NaN, Double.NaN).get(0);
// tube3.setMotor(id, m);
// tube3.setMotorOverhang(0.02);
rocket.getDefaultConfiguration().setFlightConfigurationID(id);
// tube3.setIgnitionEvent(MotorMount.IgnitionEvent.NEVER);
rocket.getDefaultConfiguration().setAllStages();
return rocket;
}
public static Rocket makeTwoStageTestRocket() {
// TODO: get units correct, these units are prob wrong, are lengths are CM, mass are grams
final double R = 2.5 / 2; // cm
final double BT_T = 0.1;
Rocket rocket = makeSingleStageTestRocket();
Stage stage = new Stage();
stage.setName("Booster");
BodyTube boosterTube = new BodyTube(9.0, R, BT_T);
stage.addChild(boosterTube);
TubeCoupler coupler = new TubeCoupler();
coupler.setOuterRadiusAutomatic(true);
coupler.setThickness(BT_T);
coupler.setLength(3.0);
coupler.setRelativePosition(Position.TOP);
coupler.setPositionValue(-1.5);
boosterTube.addChild(coupler);
TrapezoidFinSet finset = new TrapezoidFinSet();
finset.setFinCount(3);
finset.setRootChord(5.0);
finset.setTipChord(5.0);
finset.setHeight(3.0);
finset.setThickness(0.005);
finset.setSweepAngle(40.0);
finset.setRelativePosition(Position.BOTTOM);
finset.setPositionValue(-0.25);
finset.setBaseRotation(Math.PI / 2);
boosterTube.addChild(finset);
rocket.addChild(stage);
return rocket;
}
}