Merge pull request #1753 from SiboVG/issue-1621

Write unit tests for flight events
This commit is contained in:
Sibo Van Gool 2022-11-08 21:41:10 +01:00 committed by GitHub
commit b1777bb36b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 133 additions and 32 deletions

View File

@ -308,7 +308,7 @@ public class Simulation implements ChangeSource, Cloneable {
*/
public Status getStatus() {
mutex.verify();
if (status == Status.UPTODATE || status == Status.LOADED) {
if (isStatusUpToDate(status)) {
if (rocket.getFunctionalModID() != simulatedRocketID || !options.equals(simulatedConditions)) {
status = Status.OUTDATED;
}
@ -331,6 +331,14 @@ public class Simulation implements ChangeSource, Cloneable {
return status;
}
/**
* Returns true is the status indicates that the simulation data is up-to-date.
* @param status status of the simulation to check for if its data is up-to-date
*/
public static boolean isStatusUpToDate(Status status) {
return status == Status.UPTODATE || status == Status.LOADED || status == Status.EXTERNAL;
}
/**

View File

@ -6,8 +6,6 @@ import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
import net.sf.openrocket.simulation.listeners.SimulationListener;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import net.sf.openrocket.util.TestRockets;
import org.junit.Assert;
@ -35,11 +33,9 @@ public class DisableStageTest extends BaseTestCase {
simDisabled.getOptions().setISAAtmosphere(true);
simDisabled.getOptions().setTimeStep(0.05);
SimulationListener simulationListener = new AbstractSimulationListener();
// Since there are no stages, the simulation should throw an exception.
try {
simDisabled.simulate(simulationListener);
simDisabled.simulate();
} catch (SimulationException e) {
if (!(e instanceof MotorIgnitionException)) {
Assert.fail("Simulation should have thrown a MotorIgnitionException");
@ -56,7 +52,7 @@ public class DisableStageTest extends BaseTestCase {
simDisabled.getActiveConfiguration().setAllStages(); // Re-enable all stages.
compareSims(simOriginal, simDisabled, simulationListener, delta);
compareSims(simOriginal, simDisabled, delta);
}
/**
@ -83,9 +79,7 @@ public class DisableStageTest extends BaseTestCase {
simDisabled.getOptions().setISAAtmosphere(true);
simDisabled.getOptions().setTimeStep(0.05);
SimulationListener simulationListener = new AbstractSimulationListener();
compareSims(simRemoved, simDisabled, simulationListener, delta);
compareSims(simRemoved, simDisabled, delta);
//// Test re-enableing the stage.
Rocket rocketOriginal = TestRockets.makeBeta();
@ -96,7 +90,7 @@ public class DisableStageTest extends BaseTestCase {
simDisabled.getActiveConfiguration().setAllStages();
compareSims(simOriginal, simDisabled, simulationListener, delta);
compareSims(simOriginal, simDisabled, delta);
}
/**
@ -173,9 +167,7 @@ public class DisableStageTest extends BaseTestCase {
simDisabled.getOptions().setISAAtmosphere(true);
simDisabled.getOptions().setTimeStep(0.05);
SimulationListener simulationListener = new AbstractSimulationListener();
compareSims(simRemoved, simDisabled, simulationListener, delta);
compareSims(simRemoved, simDisabled, delta);
//// Test re-enableing the stage.
Rocket rocketOriginal = TestRockets.makeFalcon9Heavy();
@ -186,7 +178,7 @@ public class DisableStageTest extends BaseTestCase {
simDisabled.getActiveConfiguration().setAllStages();
compareSims(simOriginal, simDisabled, simulationListener, delta);
compareSims(simOriginal, simDisabled, delta);
}
/**
@ -214,11 +206,9 @@ public class DisableStageTest extends BaseTestCase {
simDisabled.getOptions().setISAAtmosphere(true);
simDisabled.getOptions().setTimeStep(0.05);
SimulationListener simulationListener = new AbstractSimulationListener();
// There should be no motors left at this point, so a no motors exception should be thrown
try {
simRemoved.simulate(simulationListener);
simRemoved.simulate();
} catch (SimulationException e) {
if (!(e instanceof MotorIgnitionException)) {
Assert.fail("Simulation failed: " + e);
@ -226,7 +216,7 @@ public class DisableStageTest extends BaseTestCase {
}
try {
simDisabled.simulate(simulationListener);
simDisabled.simulate();
} catch (SimulationException e) {
if (!(e instanceof MotorIgnitionException)) {
Assert.fail("Simulation failed: " + e);
@ -242,7 +232,7 @@ public class DisableStageTest extends BaseTestCase {
simDisabled.getActiveConfiguration().setAllStages();
compareSims(simOriginal, simDisabled, simulationListener, delta);
compareSims(simOriginal, simDisabled, delta);
}
/**
@ -259,13 +249,11 @@ public class DisableStageTest extends BaseTestCase {
* - groundHitVelocity
* @param simExpected the expected simulation results
* @param simActual the actual simulation results
* @param simulationListener the simulation listener to use for the comparison
* @param delta the error margin for the comparison (e.g. 0.05 = 5 % error margin)
*/
private void compareSims(Simulation simExpected, Simulation simActual,
SimulationListener simulationListener, double delta) {
private void compareSims(Simulation simExpected, Simulation simActual, double delta) {
try {
simExpected.simulate(simulationListener);
simExpected.simulate();
double maxAltitudeOriginal = simExpected.getSimulatedData().getMaxAltitude();
double maxVelocityOriginal = simExpected.getSimulatedData().getMaxVelocity();
double maxMachNumberOriginal = simExpected.getSimulatedData().getMaxMachNumber();
@ -274,7 +262,7 @@ public class DisableStageTest extends BaseTestCase {
double launchRodVelocityOriginal = simExpected.getSimulatedData().getLaunchRodVelocity();
double deploymentVelocityOriginal = simExpected.getSimulatedData().getDeploymentVelocity();
simActual.simulate(simulationListener);
simActual.simulate();
double maxAltitudeDisabled = simActual.getSimulatedData().getMaxAltitude();
double maxVelocityDisabled = simActual.getSimulatedData().getMaxVelocity();
double maxMachNumberDisabled = simActual.getSimulatedData().getMaxMachNumber();

View File

@ -0,0 +1,107 @@
package net.sf.openrocket.simulation;
import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import net.sf.openrocket.util.TestRockets;
import org.junit.Test;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
/**
* Tests to verify that simulations contain all the expected flight events.
*/
public class FlightEventsTest extends BaseTestCase {
/**
* Tests for a single stage design.
*/
@Test
public void testSingleStage() throws SimulationException {
Rocket rocket = TestRockets.makeEstesAlphaIII();
Simulation sim = new Simulation(rocket);
sim.getOptions().setISAAtmosphere(true);
sim.getOptions().setTimeStep(0.05);
sim.setFlightConfigurationId(TestRockets.TEST_FCID_0);
sim.simulate();
// Test branch count
int branchCount = sim.getSimulatedData().getBranchCount();
assertEquals(" Single stage simulation invalid branch count", 1, branchCount);
FlightEvent.Type[] expectedEventTypes = {FlightEvent.Type.LAUNCH, FlightEvent.Type.IGNITION, FlightEvent.Type.LIFTOFF,
FlightEvent.Type.LAUNCHROD, FlightEvent.Type.BURNOUT, FlightEvent.Type.EJECTION_CHARGE, FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT,
FlightEvent.Type.APOGEE, FlightEvent.Type.GROUND_HIT, FlightEvent.Type.SIMULATION_END};
// Test event count
FlightDataBranch branch = sim.getSimulatedData().getBranch(0);
List<FlightEvent> eventList = branch.getEvents();
List<FlightEvent.Type> eventTypes = eventList.stream().map(FlightEvent::getType).collect(Collectors.toList());
assertEquals(" Single stage simulation invalid number of events", expectedEventTypes.length, eventTypes.size());
// Test that all expected events are present, and in the right order
for (int i = 0; i < expectedEventTypes.length; i++) {
assertSame(" Flight type " + expectedEventTypes[i] + " not found in single stage simulation",
eventTypes.get(i), expectedEventTypes[i]);
}
}
/**
* Tests for a multi-stage design.
*/
@Test
public void testMultiStage() throws SimulationException {
Rocket rocket = TestRockets.makeFalcon9Heavy();
Simulation sim = new Simulation(rocket);
sim.getOptions().setISAAtmosphere(true);
sim.getOptions().setTimeStep(0.05);
rocket.getSelectedConfiguration().setAllStages();
FlightConfigurationId fcid = rocket.getSelectedConfiguration().getFlightConfigurationID();
sim.setFlightConfigurationId(fcid);
sim.simulate();
// Test branch count
int branchCount = sim.getSimulatedData().getBranchCount();
assertEquals(" Multi-stage simulation invalid branch count", 3, branchCount);
for (int b = 0; b < 3; b++) {
FlightEvent.Type[] expectedEventTypes;
switch (b) {
case 0:
expectedEventTypes = new FlightEvent.Type[]{FlightEvent.Type.LAUNCH, FlightEvent.Type.IGNITION, FlightEvent.Type.IGNITION,
FlightEvent.Type.LIFTOFF, FlightEvent.Type.LAUNCHROD, FlightEvent.Type.APOGEE, FlightEvent.Type.BURNOUT,
FlightEvent.Type.BURNOUT, FlightEvent.Type.EJECTION_CHARGE, FlightEvent.Type.EJECTION_CHARGE,
FlightEvent.Type.STAGE_SEPARATION, FlightEvent.Type.STAGE_SEPARATION, FlightEvent.Type.TUMBLE, FlightEvent.Type.GROUND_HIT,
FlightEvent.Type.SIMULATION_END};
break;
case 1:
case 2:
expectedEventTypes = new FlightEvent.Type[]{FlightEvent.Type.TUMBLE, FlightEvent.Type.GROUND_HIT,
FlightEvent.Type.SIMULATION_END};
break;
default:
throw new IllegalStateException("Invalid branch number " + b);
}
// Test event count
FlightDataBranch branch = sim.getSimulatedData().getBranch(b);
List<FlightEvent> eventList = branch.getEvents();
List<FlightEvent.Type> eventTypes = eventList.stream().map(FlightEvent::getType).collect(Collectors.toList());
assertEquals(" Multi-stage simulation, branch " + b + " invalid number of events", expectedEventTypes.length, eventTypes.size());
// Test that all expected events are present, and in the right order
for (int i = 0; i < expectedEventTypes.length; i++) {
assertSame(" Flight type " + expectedEventTypes[i] + ", branch " + b + " not found in multi-stage simulation",
eventTypes.get(i), expectedEventTypes[i]);
}
}
}
}

View File

@ -504,8 +504,7 @@ public class SimulationPanel extends JPanel {
private void openDialog(final Simulation sim) {
boolean plotMode = false;
if (sim.hasSimulationData() && (sim.getStatus() == Status.UPTODATE || sim.getStatus() == Status.LOADED
|| sim.getStatus() == Status.EXTERNAL)) {
if (sim.hasSimulationData() && Simulation.isStatusUpToDate(sim.getStatus())) {
plotMode = true;
}
openDialog(plotMode, sim);

View File

@ -60,7 +60,7 @@ import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;
/*
* It should be possible to simplify this code quite a bit by using a single Renderer instance for
* TODO: It should be possible to simplify this code quite a bit by using a single Renderer instance for
* both datasets and the legend. But for now, the renderers are queried for the line color information
* and this is held in the Legend.
*/

View File

@ -857,8 +857,8 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
// Re-run the present simulation(s)
List<Simulation> sims = new LinkedList<>();
for (Simulation sim : document.getSimulations()) {
if (sim.getStatus() == Simulation.Status.UPTODATE || sim.getStatus() == Simulation.Status.LOADED
|| !document.getRocket().getFlightConfiguration(sim.getFlightConfigurationId()).hasMotors())
if (Simulation.isStatusUpToDate(sim.getStatus()) ||
!document.getRocket().getFlightConfiguration(sim.getFlightConfigurationId()).hasMotors())
continue;
// Find a Simulation based on the current flight configuration

View File

@ -292,8 +292,7 @@ public class SimulationEditDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
// If the simulation is out of date, run the simulation.
if (simulationList[0].getStatus() != Simulation.Status.UPTODATE &&
simulationList[0].getStatus() != Simulation.Status.LOADED) {
if (!Simulation.isStatusUpToDate(simulationList[0].getStatus())) {
new SimulationRunDialog(SimulationEditDialog.this.parentWindow, document, simulationList[0]).setVisible(true);
}