diff --git a/isis/src/base/objs/CSMCamera/CSMCamera.cpp b/isis/src/base/objs/CSMCamera/CSMCamera.cpp index aec54ee598..27109ff108 100644 --- a/isis/src/base/objs/CSMCamera/CSMCamera.cpp +++ b/isis/src/base/objs/CSMCamera/CSMCamera.cpp @@ -861,14 +861,28 @@ namespace Isis { */ std::vector CSMCamera::getParameterIndices(QStringList paramList) const { std::vector parameterIndices; + QStringList failedParams; for (int i = 0; i < paramList.size(); i++) { + bool found = false; for (int j = 0; j < m_model->getNumParameters(); j++) { if (QString::compare(QString::fromStdString(m_model->getParameterName(j)).trimmed(), paramList[i].trimmed(), Qt::CaseInsensitive) == 0) { parameterIndices.push_back(j); + found = true; + break; } } + + if (!found) { + failedParams.push_back(paramList[i]); + } + } + + if (!failedParams.empty()) { + QString msg = "Failed to find indices for the following parameters [" + + failedParams.join(",") + "]."; + throw IException(IException::User, msg, _FILEINFO_); } return parameterIndices; } diff --git a/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.cpp b/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.cpp index ea22d04e6a..12b70fb056 100644 --- a/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.cpp +++ b/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.cpp @@ -209,28 +209,6 @@ namespace Isis { } - /** - * Applies the parameter corrections - * - * @param corrections Vector of corrections to apply - * - * @throws IException::Unknown "Instrument position is NULL, but position solve option is - * [not NoPositionFactors]" - * @throws IException::Unknown "Instrument position is NULL, but pointing solve option is - * [not NoPointingFactors]" - * @throws IException::Unknown "Unable to apply parameter corrections to AbstractBundleObservation." - * - * @return @b bool Returns true upon successful application of corrections - * - * @internal - * @todo always returns true? - */ -// FIXME: can this work at parent level or should be pure virtual? - bool AbstractBundleObservation::applyParameterCorrections(LinearAlgebra::Vector corrections) { - return false; - } - - /** * Sets the index for the observation * diff --git a/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.h b/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.h index 00d1832673..b396dd38d8 100644 --- a/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.h +++ b/isis/src/control/objs/BundleUtilities/AbstractBundleObservation.h @@ -67,7 +67,7 @@ namespace Isis { virtual const BundleObservationSolveSettingsQsp solveSettings() = 0; virtual int numberParameters() = 0; - virtual bool applyParameterCorrections(LinearAlgebra::Vector corrections); + virtual bool applyParameterCorrections(LinearAlgebra::Vector corrections) = 0; virtual void bundleOutputString(std::ostream &fpOut,bool errorPropagation) = 0; virtual QString bundleOutputCSV(bool errorPropagation) = 0; @@ -87,9 +87,9 @@ namespace Isis { protected: QString m_observationNumber; /**< This is typically equivalent to serial number except in the case of "observation mode" (e.g. - Lunar Orbiter) where for each image in the - observation, the observation number is the serial number - augmented with an additional integer. **/ + Lunar Orbiter) where the observation number is + the portion of the serial number shared between + all of the images in the observation. **/ int m_index; //!< Index of this observation. //! Map between cube serial number and BundleImage pointers. QMap m_cubeSerialNumberToBundleImageMap; @@ -97,7 +97,6 @@ namespace Isis { QStringList m_imageNames; //!< List of all cube names. QString m_instrumentId; //!< Spacecraft instrument id. - // TODO??? change these to LinearAlgebra vectors... LinearAlgebra::Vector m_weights; //!< Parameter weights. //! Cumulative parameter correction vector. LinearAlgebra::Vector m_corrections; diff --git a/isis/src/control/objs/BundleUtilities/BundleObservation.cpp b/isis/src/control/objs/BundleUtilities/BundleObservation.cpp index b6951f6792..60dbbc49cd 100644 --- a/isis/src/control/objs/BundleUtilities/BundleObservation.cpp +++ b/isis/src/control/objs/BundleUtilities/BundleObservation.cpp @@ -34,8 +34,6 @@ namespace Isis { BundleObservation::BundleObservation() { m_instrumentPosition = NULL; m_instrumentRotation = NULL; - // m_solveSettings? - // m_bundleTargetBody ? } @@ -49,7 +47,8 @@ namespace Isis { * @param bundleTargetBody QSharedPointer to the target body of the observation */ BundleObservation::BundleObservation(BundleImageQsp image, QString observationNumber, - QString instrumentId, BundleTargetBodyQsp bundleTargetBody) : AbstractBundleObservation(image, observationNumber, instrumentId, bundleTargetBody) { + QString instrumentId, BundleTargetBodyQsp bundleTargetBody) : + AbstractBundleObservation(image, observationNumber, instrumentId, bundleTargetBody) { m_bundleTargetBody = bundleTargetBody; m_instrumentRotation = NULL; m_instrumentPosition = NULL; @@ -66,10 +65,6 @@ namespace Isis { (image->camera()->instrumentRotation() ? image->camera()->instrumentRotation() : NULL) : NULL); - - // set the observations target body spice rotation object from the primary image in the - // observation (this is, by design at the moment, the first image added to the observation) - // if the image, camera, or instrument position/orientation is null, then set to null } } @@ -83,7 +78,7 @@ namespace Isis { m_instrumentPosition = src.m_instrumentPosition; m_instrumentRotation = src.m_instrumentRotation; m_solveSettings = src.m_solveSettings; - // why not m_targetBody? + m_bundleTargetBody = src.m_bundleTargetBody; } @@ -111,7 +106,7 @@ namespace Isis { m_instrumentPosition = src.m_instrumentPosition; m_instrumentRotation = src.m_instrumentRotation; m_solveSettings = src.m_solveSettings; - // why not m_targetBody? + m_bundleTargetBody = src.m_bundleTargetBody; } return *this; } @@ -148,12 +143,11 @@ namespace Isis { m_adjustedSigmas.resize(nParameters); m_adjustedSigmas.clear(); m_aprioriSigmas.resize(nParameters); - for ( int i = 0; i < nParameters; i++) // initialize apriori sigmas to -1.0 + for ( int i = 0; i < nParameters; i++) { m_aprioriSigmas[i] = Isis::Null; + } if (!initParameterWeights()) { - // TODO: some message here!!!!!!!!!!! - // TODO: do we need this??? initParameterWeights() never returns false... return false; } @@ -212,25 +206,26 @@ namespace Isis { BundleImageQsp image = at(i); SpicePosition *spicePosition = image->camera()->instrumentPosition(); + // If this image isn't the first, copy the position from the first if (i > 0) { spicePosition->SetPolynomialDegree(m_solveSettings->spkSolveDegree()); spicePosition->SetOverrideBaseTime(positionBaseTime, positiontimeScale); spicePosition->SetPolynomial(posPoly1, posPoly2, posPoly3, m_solveSettings->positionInterpolationType()); } + // Otherwise we need to fit the initial position else { // first, set the degree of the spk polynomial to be fit for a priori values spicePosition->SetPolynomialDegree(m_solveSettings->spkDegree()); - // now, set what kind of interpolation to use (SPICE, memcache, hermitecache, polynomial - // function, or polynomial function over constant hermite spline) - // TODO: verify - I think this actually performs the a priori fit + // now, set what kind of interpolation to use (polynomial function or + // polynomial function over hermite spline) spicePosition->SetPolynomial(m_solveSettings->positionInterpolationType()); - // finally, set the degree of the spk polynomial actually used in the bundle adjustment + // finally, set the degree of the position polynomial actually used in the bundle adjustment spicePosition->SetPolynomialDegree(m_solveSettings->spkSolveDegree()); - if (m_instrumentPosition) { // ??? TODO: why is this different from rotation code below??? + if (m_instrumentPosition) { positionBaseTime = m_instrumentPosition->GetBaseTime(); positiontimeScale = m_instrumentPosition->GetTimeScale(); m_instrumentPosition->GetPolynomial(posPoly1, posPoly2, posPoly3); @@ -250,22 +245,23 @@ namespace Isis { BundleImageQsp image = at(i); SpiceRotation *spicerotation = image->camera()->instrumentRotation(); + // If this image isn't the first, copy the pointing from the first if (i > 0) { spicerotation->SetPolynomialDegree(m_solveSettings->ckSolveDegree()); spicerotation->SetOverrideBaseTime(rotationBaseTime, rotationtimeScale); spicerotation->SetPolynomial(anglePoly1, anglePoly2, anglePoly3, m_solveSettings->pointingInterpolationType()); } + // Otherwise we need to fit the initial pointing else { - // first, set the degree of the spk polynomial to be fit for a priori values + // first, set the degree of the polynomial to be fit for a priori values spicerotation->SetPolynomialDegree(m_solveSettings->ckDegree()); - // now, set what kind of interpolation to use (SPICE, memcache, hermitecache, polynomial - // function, or polynomial function over constant hermite spline) - // TODO: verify - I think this actually performs the a priori fit + // now, set what kind of interpolation to use (polynomial function or + // polynomial function over a pointing cache) spicerotation->SetPolynomial(m_solveSettings->pointingInterpolationType()); - // finally, set the degree of the spk polynomial actually used in the bundle adjustment + // finally, set the degree of the pointing polynomial actually used in the bundle adjustment spicerotation->SetPolynomialDegree(m_solveSettings->ckSolveDegree()); rotationBaseTime = spicerotation->GetBaseTime(); diff --git a/isis/src/control/objs/BundleUtilities/BundleObservationSolveSettings.cpp b/isis/src/control/objs/BundleUtilities/BundleObservationSolveSettings.cpp index f69deda9c9..63dc77cc50 100644 --- a/isis/src/control/objs/BundleUtilities/BundleObservationSolveSettings.cpp +++ b/isis/src/control/objs/BundleUtilities/BundleObservationSolveSettings.cpp @@ -459,6 +459,13 @@ namespace Isis { // =============================================================================================// + /** + * Convert a string to a CSM solve option enumeration value. + * + * @param option The option as a string + * + * @return @b CSMSolveOption The option's enumeration value + */ BundleObservationSolveSettings::CSMSolveOption BundleObservationSolveSettings::stringToCSMSolveOption(QString option) { if (option.compare("NoCSMParameters", Qt::CaseInsensitive) == 0) { @@ -481,6 +488,13 @@ namespace Isis { } + /** + * Convert a CSM solve option enumeration value to a string. + * + * @param option The option's enumeration value + * + * @return @b QString The option as a string + */ QString BundleObservationSolveSettings::csmSolveOptionToString(CSMSolveOption option) { if (option == BundleObservationSolveSettings::NoCSMParameters) { return "NoCSMParameters"; @@ -502,7 +516,13 @@ namespace Isis { } - + /** + * Convert a string to its CSM parameter set enumeration value. + * + * @param set The set name + * + * @return @b csm::param::Set The set's enumeration value + */ csm::param::Set BundleObservationSolveSettings::stringToCSMSolveSet(QString set) { if (set.compare("VALID", Qt::CaseInsensitive) == 0) { return csm::param::VALID; @@ -520,6 +540,14 @@ namespace Isis { } } + + /** + * Convert a CSM parameter set enumeration value to a string. + * + * @param set The set's enumeration value + * + * @return @b QString The set's name + */ QString BundleObservationSolveSettings::csmSolveSetToString(csm::param::Set set) { if (set == csm::param::VALID) { return "VALID"; @@ -538,6 +566,13 @@ namespace Isis { } + /** + * Convert a string to its CSM parameter type enumeration value. + * + * @param type The type name + * + * @return @b csm::param::Type The types's enumeration value + */ csm::param::Type BundleObservationSolveSettings::stringToCSMSolveType(QString type) { if (type.compare("NONE", Qt::CaseInsensitive) == 0) { return csm::param::NONE; @@ -559,6 +594,13 @@ namespace Isis { } + /** + * Convert a CSM parameter type enumeration value to a string. + * + * @param type The type's enumeration value + * + * @return @b QString The type's name + */ QString BundleObservationSolveSettings::csmSolveTypeToString(csm::param::Type type) { if (type == csm::param::NONE) { return "NONE"; @@ -580,40 +622,76 @@ namespace Isis { } + /** + * Set the set of CSM parameters to solve for. See the CSM API documentation + * for what the different set values mean. + * + * @param set The set to solve for + */ void BundleObservationSolveSettings::setCSMSolveSet(csm::param::Set set) { m_csmSolveOption = BundleObservationSolveSettings::Set; m_csmSolveSet = set; } + /** + * Set the type of CSM parameters to solve for. + * + * @param type The parameter type to solve for + */ void BundleObservationSolveSettings::setCSMSolveType(csm::param::Type type) { m_csmSolveOption = BundleObservationSolveSettings::Type; m_csmSolveType = type; } + /** + * Set an explicit list of CSM parameters to solve for. + * + * @param list The names of the parameters to solve for + */ void BundleObservationSolveSettings::setCSMSolveParameterList(QStringList list) { m_csmSolveOption = BundleObservationSolveSettings::List; m_csmSolveList = list; } + /** + * Get how the CSM parameters to solve for are specified for this observation. + * + * @return @b CSMSolveOption + */ BundleObservationSolveSettings::CSMSolveOption BundleObservationSolveSettings::csmSolveOption() const { return m_csmSolveOption; } + /** + * Get the set of CSM parameters to solve for + * + * @return @b csm::param::Set The CSM parameter set to solve for + */ csm::param::Set BundleObservationSolveSettings::csmParameterSet() const { return m_csmSolveSet; } + /** + * Get the type of CSM parameters to solve for + * + * @return @b csm::param::Type The CSM parameter type to solve for + */ csm::param::Type BundleObservationSolveSettings::csmParameterType() const { return m_csmSolveType; } + /** + * Get the list of CSM parameters to solve for + * + * @return @b QStringList The names of the CSM parameters to solve for + */ QStringList BundleObservationSolveSettings::csmParameterList() const { return m_csmSolveList; } diff --git a/isis/src/control/objs/BundleUtilities/BundleObservationSolveSettings.h b/isis/src/control/objs/BundleUtilities/BundleObservationSolveSettings.h index 76154dc61a..3cddd1489a 100644 --- a/isis/src/control/objs/BundleUtilities/BundleObservationSolveSettings.h +++ b/isis/src/control/objs/BundleUtilities/BundleObservationSolveSettings.h @@ -227,10 +227,13 @@ class BundleObservationSolveSettings { QSet m_observationNumbers; //!< Associated observation numbers for these settings. // CSM related parameters - CSMSolveOption m_csmSolveOption; - csm::param::Set m_csmSolveSet; - csm::param::Type m_csmSolveType; - QStringList m_csmSolveList; + CSMSolveOption m_csmSolveOption; //!< How the CSM solution is specified + csm::param::Set m_csmSolveSet; /**< The CSM parameter set to solve for. Only valid + if the solve option is Set.*/ + csm::param::Type m_csmSolveType; /**< The CSM parameter type to solve for. Only valid + if the solve option is Type.*/ + QStringList m_csmSolveList; /**< The names of the CSM parameters to solve for. Only + valid if the solve option is List.*/ // pointing related parameters //! Option for how to solve for instrument pointing. diff --git a/isis/src/control/objs/BundleUtilities/BundleObservationVector.cpp b/isis/src/control/objs/BundleUtilities/BundleObservationVector.cpp index 9cf14b0771..abdd5b8863 100644 --- a/isis/src/control/objs/BundleUtilities/BundleObservationVector.cpp +++ b/isis/src/control/objs/BundleUtilities/BundleObservationVector.cpp @@ -126,26 +126,22 @@ namespace Isis { else { // create new BundleObservation and append to this vector - bool isIsisObservation = true; - - isIsisObservation = bundleImage->camera()->GetCameraType() != Camera::Csm; - - AbstractBundleObservation *observation = NULL; + bool isIsisObservation = bundleImage->camera()->GetCameraType() != Camera::Csm; if (isIsisObservation) { - observation = new BundleObservation(bundleImage, - observationNumber, - instrumentId, - bundleSettings->bundleTargetBody()); + bundleObservation.reset(new BundleObservation(bundleImage, + observationNumber, + instrumentId, + bundleSettings->bundleTargetBody())); } else { - observation = new CsmBundleObservation(bundleImage, - observationNumber, - instrumentId, - bundleSettings->bundleTargetBody()); + bundleObservation.reset(new CsmBundleObservation(bundleImage, + observationNumber, + instrumentId, + bundleSettings->bundleTargetBody())); } - if (!observation) { + if (!bundleObservation) { QString message = "Unable to allocate new BundleObservation "; message += "for " + bundleImage->fileName(); throw IException(IException::Programmer, message, _FILEINFO_); @@ -163,8 +159,7 @@ namespace Isis { solveSettings = bundleSettings->observationSolveSettings(observationNumber); } - observation->setSolveSettings(solveSettings); - bundleObservation.reset(observation); + bundleObservation->setSolveSettings(solveSettings); bundleObservation->setIndex(size()); diff --git a/isis/src/control/objs/BundleUtilities/unitTest.cpp b/isis/src/control/objs/BundleUtilities/unitTest.cpp index e750be21b6..d275314988 100755 --- a/isis/src/control/objs/BundleUtilities/unitTest.cpp +++ b/isis/src/control/objs/BundleUtilities/unitTest.cpp @@ -613,27 +613,11 @@ int main(int argc, char *argv[]) { */ BundleObservationVector bov; BundleSettingsQsp bundleSettings = BundleSettingsQsp(new BundleSettings); - // BundleObservation *obs1 = bov.addNew(bi2, "obs1", "InstrumentIdBOV", bundleSettings); - //qDebug() << obs1->formatBundleOutputString(true); - //obs1 = bov.observationByCubeSerialNumber("obs1"); - //BundleObservation *obs2 = bov.addNew(bundleImage, "obs2", "InstrumentIdBOV", bundleSettings); - //qDebug() << obs2->formatBundleOutputString(true); qDebug() << "number of parameters: " << toString(bov.numberParameters()); - -#if 0 - BundleObservation obs1b = *bov.getObservationByCubeSerialNumber("obs1"); - qDebug() << "same observation?" << toString((obs1 == obs1b)); - qDebug() << obs1b.formatBundleOutputString(true); -#endif - // Following segfaults (see #4157) -// qDebug() << "init exterior orientiation successful? " << toString(bov.initializeExteriorOrientation()); qDebug() << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; qDebug() << ""; qDebug() << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; qDebug() << "Testing BundleControlPoint..."; - #if 0 - TEST COVERAGE (SCOPE) FOR THIS SOURCE FILE: 100% - #endif // #1 Test free point with default settings (solveRadius=false), apriori coordinates set, but no // sigmas (other settings: observation mode = false, update =false, errorProp = false) qDebug() << "BCP test 1 - Create FreePoint with free point containing 2 measures " diff --git a/isis/tests/CSMCameraTests.cpp b/isis/tests/CSMCameraTests.cpp index 1bcf526ce1..8aa3df5b51 100644 --- a/isis/tests/CSMCameraTests.cpp +++ b/isis/tests/CSMCameraTests.cpp @@ -253,20 +253,47 @@ TEST_F(CSMCameraSetFixture, EmissionAngle) { } -TEST_F(CSMCameraFixture, getParameterIndices) { +TEST_F(CSMCameraSetFixture, GroundPartials) { + std::vector expectedPartials = {1, 2, 3, 4, 5, 6}; + EXPECT_CALL(mockModel, computeGroundPartials(MatchEcefCoord(groundPt))) + .Times(1) + .WillOnce(::testing::Return(expectedPartials)); + + std::vector groundPartials = dynamic_cast(testCam)->GroundPartials(); + ASSERT_EQ(groundPartials.size(), 6); + EXPECT_EQ(groundPartials[0], expectedPartials[0]); + EXPECT_EQ(groundPartials[1], expectedPartials[1]); + EXPECT_EQ(groundPartials[2], expectedPartials[2]); + EXPECT_EQ(groundPartials[3], expectedPartials[3]); + EXPECT_EQ(groundPartials[4], expectedPartials[4]); + EXPECT_EQ(groundPartials[5], expectedPartials[5]); +} + + +TEST_F(CSMCameraSetFixture, SensorPartials) { + std::pair expectedPartials = {1.23, -5.43}; + EXPECT_CALL(mockModel, computeSensorPartials(1, MatchEcefCoord(groundPt), 0.001, NULL, NULL)) + .Times(1) + .WillOnce(::testing::Return(expectedPartials)); + + std::vector groundPartials = + dynamic_cast(testCam)->getSensorPartials(1, testCam->GetSurfacePoint()); + ASSERT_EQ(groundPartials.size(), 2); + EXPECT_EQ(groundPartials[0], expectedPartials.first); + EXPECT_EQ(groundPartials[1], expectedPartials.second); +} + + +TEST_F(CSMCameraFixture, getParameterIndicesSet) { std::vector paramIndices = {0, 1, 2}; EXPECT_CALL(mockModel, getNumParameters()) - .Times(1) - .WillOnce(::testing::Return(3)); + .WillRepeatedly(::testing::Return(3)); EXPECT_CALL(mockModel, getParameterType(0)) - .Times(1) - .WillOnce(::testing::Return(csm::param::REAL)); + .WillRepeatedly(::testing::Return(csm::param::REAL)); EXPECT_CALL(mockModel, getParameterType(1)) - .Times(1) - .WillOnce(::testing::Return(csm::param::REAL)); + .WillRepeatedly(::testing::Return(csm::param::REAL)); EXPECT_CALL(mockModel, getParameterType(2)) - .Times(1) - .WillOnce(::testing::Return(csm::param::REAL)); + .WillRepeatedly(::testing::Return(csm::param::REAL)); std::vector indices = dynamic_cast(testCam)->getParameterIndices(csm::param::ADJUSTABLE); ASSERT_EQ(indices.size(), paramIndices.size()); @@ -276,6 +303,97 @@ TEST_F(CSMCameraFixture, getParameterIndices) { } +TEST_F(CSMCameraFixture, getParameterIndicesType) { + std::vector paramIndices = {1, 2}; + EXPECT_CALL(mockModel, getNumParameters()) + .WillRepeatedly(::testing::Return(3)); + EXPECT_CALL(mockModel, getParameterType(0)) + .WillRepeatedly(::testing::Return(csm::param::FIXED)); + EXPECT_CALL(mockModel, getParameterType(1)) + .WillRepeatedly(::testing::Return(csm::param::REAL)); + EXPECT_CALL(mockModel, getParameterType(2)) + .WillRepeatedly(::testing::Return(csm::param::REAL)); + + std::vector indices = dynamic_cast(testCam)->getParameterIndices(csm::param::REAL); + ASSERT_EQ(indices.size(), paramIndices.size()); + for (size_t i = 0; i < paramIndices.size(); i++) { + EXPECT_EQ(indices[i], paramIndices[i]) << "Error at index " << i; + } +} + + +TEST_F(CSMCameraFixture, getParameterIndicesList) { + std::vector paramIndices = {2, 0}; + EXPECT_CALL(mockModel, getNumParameters()) + .WillRepeatedly(::testing::Return(3)); + EXPECT_CALL(mockModel, getParameterName(0)) + .WillRepeatedly(::testing::Return("Parameter 1")); + EXPECT_CALL(mockModel, getParameterName(1)) + .WillRepeatedly(::testing::Return("Parameter 2")); + EXPECT_CALL(mockModel, getParameterName(2)) + .WillRepeatedly(::testing::Return("Parameter 3")); + + QStringList paramList = {"Parameter 3", "Parameter 1"}; + + std::vector indices = dynamic_cast(testCam)->getParameterIndices(paramList); + ASSERT_EQ(indices.size(), paramIndices.size()); + for (size_t i = 0; i < paramIndices.size(); i++) { + EXPECT_EQ(indices[i], paramIndices[i]) << "Error at index " << i; + } +} + + +TEST_F(CSMCameraFixture, getParameterIndicesListComparison) { + std::vector paramIndices = {2, 0, 1}; + EXPECT_CALL(mockModel, getNumParameters()) + .WillRepeatedly(::testing::Return(3)); + EXPECT_CALL(mockModel, getParameterName(0)) + .WillRepeatedly(::testing::Return("Parameter 1 ")); + EXPECT_CALL(mockModel, getParameterName(1)) + .WillRepeatedly(::testing::Return(" Parameter 2")); + EXPECT_CALL(mockModel, getParameterName(2)) + .WillRepeatedly(::testing::Return("Parameter 3")); + + QStringList paramList = {"PARAMETER 3", " Parameter 1", "parameter 2 "}; + + std::vector indices = dynamic_cast(testCam)->getParameterIndices(paramList); + ASSERT_EQ(indices.size(), paramIndices.size()); + for (size_t i = 0; i < paramIndices.size(); i++) { + EXPECT_EQ(indices[i], paramIndices[i]) << "Error at index " << i; + } +} + + +TEST_F(CSMCameraFixture, getParameterIndicesListError) { + std::vector paramIndices = {3, 1}; + EXPECT_CALL(mockModel, getNumParameters()) + .WillRepeatedly(::testing::Return(3)); + EXPECT_CALL(mockModel, getParameterName(0)) + .WillRepeatedly(::testing::Return("Parameter 1")); + EXPECT_CALL(mockModel, getParameterName(1)) + .WillRepeatedly(::testing::Return("Parameter 2")); + EXPECT_CALL(mockModel, getParameterName(2)) + .WillRepeatedly(::testing::Return("Parameter 3")); + + QStringList paramList = {"Parameter 4", "Parameter 1", "Parameter 0"}; + + try + { + dynamic_cast(testCam)->getParameterIndices(paramList); + } + catch(Isis::IException &e) + { + EXPECT_TRUE(e.toString().toLatin1().contains("Failed to find indices for the following parameters [" + "Parameter 4,Parameter 0].")) << e.toString().toStdString(); + } + catch(...) + { + FAIL() << "Expected an IException with message \"" + "Failed to find indices for the following parameters [Parameter 4,Parameter 0].\""; + } +} + + TEST_F(CSMCameraFixture, applyParameterCorrection) { EXPECT_CALL(mockModel, getParameterValue(2)) .Times(1)