| // DiseaseModelScenarioTest.java |
| package org.eclipse.stem.diseasemodels.standard.tests; |
| |
| /******************************************************************************* |
| * Copyright (c) 2006 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.StringTokenizer; |
| |
| import junit.framework.TestCase; |
| |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.stem.core.graph.Graph; |
| import org.eclipse.stem.core.graph.LabelValue; |
| import org.eclipse.stem.core.graph.NodeLabel; |
| import org.eclipse.stem.core.model.Decorator; |
| import org.eclipse.stem.core.model.Model; |
| import org.eclipse.stem.core.model.NodeDecorator; |
| import org.eclipse.stem.core.scenario.Scenario; |
| import org.eclipse.stem.core.scenario.tests.ScenarioTest; |
| import org.eclipse.stem.definitions.nodes.Region; |
| import org.eclipse.stem.diseasemodels.standard.DiseaseModel; |
| import org.eclipse.stem.diseasemodels.standard.DiseaseModelLabel; |
| import org.eclipse.stem.diseasemodels.standard.DiseaseModelLabelValue; |
| |
| /** |
| * This class is the top-level class for all test of disease models in a |
| * particular scenario. |
| */ |
| public abstract class DiseaseModelScenarioTest extends TestCase { |
| |
| protected static final String DIRECTORY = "temp"; |
| |
| /** |
| * The key for scenario 1x1 |
| */ |
| public static final String TEST_SCENARIO1x1_KEY = "1x1"; |
| |
| /** |
| * The key for scenario 1x2 |
| */ |
| public static final String TEST_SCENARIO1x2_KEY = "1x2"; |
| |
| /** |
| * The key for scenario 1x3 |
| */ |
| public static final String TEST_SCENARIO1x3_KEY = "1x3"; |
| |
| /** |
| * The key for scenario 2x2 |
| */ |
| public static final String TEST_SCENARIO2x2_KEY = "2x2"; |
| |
| /** |
| * The key for scenario 3x3 |
| */ |
| public static final String TEST_SCENARIO3x3_KEY = "3x3"; |
| |
| // TODO implement the disease model test scenarios |
| |
| // You need to un-comment the testSpecifications and then in each of the |
| // test implementations you're going to need to figure out the valid disease |
| // model label values. see StochasticSEIRScenarioTest.java etc. |
| protected static TestSpec[] testSpecifications = new TestSpec[] { new TestSpec( |
| 1, 1, TEST_SCENARIO1x1_KEY) |
| /* |
| * new TestSpec(1, 1, TEST_SCENARIO1x1_KEY), new TestSpec(1, 2, |
| * TEST_SCENARIO1x2_KEY), new TestSpec(1, 3, TEST_SCENARIO1x3_KEY), new |
| * TestSpec(2, 2, TEST_SCENARIO2x2_KEY), new TestSpec(3, 3, |
| * TEST_SCENARIO3x3_KEY) |
| */ |
| }; |
| |
| /** |
| * @param expectedLabelValues |
| * the expected label values for the test |
| * @return how many labels are expected to be updated by a disease model for |
| * each test. |
| */ |
| protected static int computeExpectedNumberOfLabels( |
| final LabelValue[][][] expectedLabelValues) { |
| return expectedLabelValues[0].length * expectedLabelValues[0][0].length; |
| } // computeExpectedNumberOfLabels |
| |
| /** |
| * @param numRows |
| * the number of rows in the lattice |
| * @param numColumns |
| * the number of columns in the lattice |
| * @return a scenario with nodes in a lattice with a disease model. |
| */ |
| public Scenario createFixture(final int numRows, final int numColumns) { |
| final Collection<NodeDecorator> DISEASE_MODELS = new ArrayList<NodeDecorator>(); |
| DISEASE_MODELS.addAll(getDiseaseModelsToTest()); |
| |
| final Model model = DiseaseModelTestUtil.createLatticeModel( |
| DISEASE_MODELS, numRows, numColumns, |
| DiseaseModelTestUtil.TEST_POPULATION_COUNT, |
| DiseaseModelTestUtil.TEST_AREA); |
| |
| final Scenario retValue = DiseaseModelTestUtil.createLatticeScenario( |
| getScenarioDecorators(model), model); |
| |
| assert retValue.sane(); |
| |
| return retValue; |
| } // createFixture |
| |
| /** |
| * Execute all of the tests specified in testSpecifications |
| */ |
| public void testDoAllTests() { |
| for (final TestSpec testSpec : testSpecifications) { |
| doTest(testSpec); |
| } |
| } // testDoAllTests |
| |
| /** |
| * Test serializing and de-serializing scenarios |
| */ |
| public void testSerializeDeserializeScenario() { |
| |
| final int[][] rowColumns = new int[][] { { 1, 1 }, { 1, 2 }, { 3, 3 } }; |
| |
| for (final int[] rowColumn : rowColumns) { |
| final Scenario fixture = createFixture(rowColumn[0], rowColumn[1]); |
| |
| final URI uri = createSerializationURI(fixture); |
| ScenarioTest.serializeDeserializeScenario(fixture, uri); |
| } |
| } // testSerializeDeserializeScenario |
| |
| /** |
| * @param testSpec |
| * a test specification |
| */ |
| private void doTest(final TestSpec testSpec) { |
| doTest(createFixture(testSpec.numRows, testSpec.numColumns), |
| testSpec.scenarioDiseaseKey); |
| } // doTest |
| |
| /** |
| * @param scenario |
| * the scenario to test |
| * @param scenarioDiseaseKey |
| * the unique identifier of the scenario test |
| */ |
| private void doTest(final Scenario scenario, final String scenarioDiseaseKey) { |
| |
| final int numSteps = getNumberOfSteps(scenarioDiseaseKey); |
| |
| // Step through the disease computation by using the actual scenario |
| // step method |
| for (int step = 0; step < numSteps; step++) { |
| // Make one step... |
| scenario.step(); |
| // ... and make sure everything looks ok |
| assertTrue(scenario.sane()); |
| |
| // Now validate the computed values for each disease model in the |
| // scenario... |
| for (final DiseaseModel diseaseModel : getDiseaseModels(scenario)) { |
| // Really only need to check this once... |
| if (step == 0) { |
| assertTrue( |
| "Disease model \"" |
| + diseaseModel.getDublinCore().getTitle() |
| + "\" \"" |
| + scenario.getDublinCore().getTitle() |
| + "\" \"" + scenarioDiseaseKey, |
| diseaseModel.getLabelsToUpdate().size() == getExpectedNumberOfLabelsToUpdate(scenarioDiseaseKey)); |
| } // if |
| |
| assertTrue(validateDiseaseModelState(scenario, |
| scenarioDiseaseKey, step, diseaseModel, |
| getExpectedDiseaseModelState(scenarioDiseaseKey, step))); |
| |
| } // for each disease model |
| } // for each step |
| |
| } // doTest |
| |
| /** |
| * @param scenario |
| * the scenario whose state is to be verified |
| * @param scenarioDiseaseKey |
| * the unique identifier of the scenario test |
| * @param step |
| * the step number in the test being verified |
| * @param expectedDiseaseModelState |
| * the disease model label values that should be present |
| */ |
| private boolean validateDiseaseModelState(final Scenario scenario, |
| final String scenarioDiseaseKey, final int step, |
| final DiseaseModel diseaseModel, |
| final LabelValue[][] expectedDiseaseModelState) { |
| final boolean retValue = true; |
| |
| final Graph canonicalGraph = scenario.getCanonicalGraph(); |
| |
| for (int row = 0; row < expectedDiseaseModelState.length; row++) { |
| for (int column = 0; column < expectedDiseaseModelState[row].length; column++) { |
| final Region region = DiseaseModelTestUtil.getRegion( |
| canonicalGraph, row, column); |
| final LabelValue labelValue = expectedDiseaseModelState[row][column]; |
| final LabelValue dmLabelValue = getCurrentDiseaseModelLabelValue( |
| region, diseaseModel); |
| assertTrue("Disease model \"" |
| + diseaseModel.getDublinCore().getTitle() + "\" (" |
| + scenarioDiseaseKey + ") step: " + step + " [" + row |
| + ", " + column + "] Got \"" + dmLabelValue.toString() |
| + "\", expected \"" + labelValue.toString() + "\"", |
| compareLabelValues(labelValue, dmLabelValue)); |
| } // for column |
| } // for row |
| |
| return retValue; |
| } // validateDiseaseModelState |
| |
| /** |
| * @param labelValue |
| * @param dmLabelValue |
| * @return <code>true</code> if the labels are "equal". We do a "fuzzy" |
| * compare on the double values. We declare them "equal" if they |
| * differ by less than a specified tolerance. |
| */ |
| protected boolean compareLabelValues(final LabelValue lableValue1, |
| final LabelValue lableValue2) { |
| boolean retValue = true; |
| final DiseaseModelLabelValue dmLV1 = (DiseaseModelLabelValue) lableValue1; |
| final DiseaseModelLabelValue dmLV2 = (DiseaseModelLabelValue) lableValue2; |
| |
| retValue = retValue |
| && DiseaseModelTestUtil.closeEnough(dmLV1.getDiseaseDeaths(), |
| dmLV2.getDiseaseDeaths()); |
| return retValue; |
| } // compareLabelValues |
| |
| /** |
| * @param fixture |
| * the scenario to test |
| * @return the URI to use to serialize and then de-serialize the scenario |
| * under test |
| */ |
| private URI createSerializationURI(final Scenario fixture) { |
| final URI uri = URI |
| .createURI(DIRECTORY + "/" + getDiseaseURIPrefix() |
| + encodeTitle(fixture.getDublinCore().getTitle()) |
| + ".scenario"); |
| return uri; |
| } // createSerializationURI |
| |
| /** |
| * @param title |
| * the title of a scenario |
| * @return the title with all whitespace removed |
| */ |
| private String encodeTitle(final String title) { |
| final StringBuilder sb = new StringBuilder(); |
| final StringTokenizer st = new StringTokenizer(title, ",.[] "); |
| while (st.hasMoreTokens()) { |
| sb.append(st.nextToken()); |
| } // while |
| return sb.toString(); |
| } // encodeTitle |
| |
| /** |
| * @param region |
| * the region node to search for a label updated by the disease |
| * model |
| * @param diseaseModel |
| * the disease model |
| * @return the current value of the label on the node updated by the disease |
| * model |
| */ |
| private LabelValue getCurrentDiseaseModelLabelValue(final Region region, |
| final DiseaseModel diseaseModel) { |
| LabelValue retValue = null; |
| for (final Object element : region.getLabels()) { |
| final NodeLabel nodeLabel = (NodeLabel) element; |
| if (nodeLabel instanceof DiseaseModelLabel) { |
| final DiseaseModelLabel diseaseModelLabel = (DiseaseModelLabel) nodeLabel; |
| // Is this label updated by the disease model? |
| if (diseaseModel.getLabelsToUpdate() |
| .contains(diseaseModelLabel)) { |
| // Yes |
| retValue = diseaseModelLabel.getCurrentValue(); |
| break; |
| } |
| } // if |
| } // for each node label |
| return retValue; |
| } // getCurrentDiseaseModelLabelValue |
| |
| /** |
| * |
| * @param scenario |
| * a scenario |
| * @return all of the disease models in the scenario. |
| */ |
| protected List<DiseaseModel> getDiseaseModels(final Scenario scenario) { |
| final List<DiseaseModel> retValue = new ArrayList<DiseaseModel>(); |
| |
| for (final Object element : scenario.getCanonicalGraph() |
| .getDecorators()) { |
| final Decorator decorator = (Decorator) element; |
| if (decorator instanceof DiseaseModel) { |
| retValue.add((DiseaseModel) decorator); |
| } |
| } // for each decorator in the canonical graph |
| return retValue; |
| } // getDiseaseModel |
| |
| /** |
| * @param diseaseScenarioKey |
| * the key identifying the test |
| * @return the number of disease model computations to execute for the test. |
| */ |
| protected abstract int getNumberOfSteps(final String diseaseScenarioKey); |
| |
| /** |
| * @param diseaseScenarioKey |
| * the key identifying the test |
| * @return the expected number of labels a disease model will update |
| */ |
| protected abstract int getExpectedNumberOfLabelsToUpdate( |
| final String diseaseScenarioKey); |
| |
| /** |
| * @param diseaseScenarioKey |
| * identifier that uniquely identifies the combination of disease |
| * and scenario. |
| * @param step |
| * the simulation step that has been completed. |
| * @return an array of disease model label values that are the expected |
| * values after the given step of the simulation. |
| */ |
| protected abstract LabelValue[][] getExpectedDiseaseModelState( |
| final String diseaseScenarioKey, final int step); |
| |
| /** |
| * @return the disease models to be tested |
| */ |
| public abstract List<NodeDecorator> getDiseaseModelsToTest(); |
| |
| /** |
| * @param model |
| * the model to generate scenario decorators for |
| * @return the scenario decorators to include in a fixture |
| */ |
| public abstract Collection<Decorator> getScenarioDecorators(Model model); |
| |
| /** |
| * @return a string to be used in a URI to prefix the scenario files being |
| * serialized for a particular disease under test. |
| */ |
| protected abstract String getDiseaseURIPrefix(); |
| |
| /** |
| * This class represents the parameters for the specification of a test |
| */ |
| protected static final class TestSpec { |
| /** |
| * The number of rows in the lattice graph |
| */ |
| public int numRows = 0; |
| |
| /** |
| * The number of columns in the lattice graph |
| */ |
| public int numColumns = 0; |
| |
| /** |
| * The scenario/disease key of the test. |
| */ |
| public String scenarioDiseaseKey = ""; |
| |
| /** |
| * @param numRows |
| * @param numColumns |
| * @param scenarioDiseaseKey |
| */ |
| protected TestSpec(final int numRows, final int numColumns, |
| final String scenarioDiseaseKey) { |
| super(); |
| this.numRows = numRows; |
| this.numColumns = numColumns; |
| this.scenarioDiseaseKey = scenarioDiseaseKey; |
| } |
| } // TestSpec |
| |
| } // DiseaseModelScenarioTest |