<commit_before>#include <MdisPlugin.h>
#include <MdisNacSensorModel.h>
#include <IsdReader.h>

#include <csm/Isd.h>

#include <gtest/gtest.h>


/**
 * Sub-class MdisNacSensorModel to get test its protected linear algebra methods.
 * 
 * We should be testing the protected methods of MdisNacSensorModel since imageToGround
 * depends on intersect, which depends on project, etc.
 */
class TestableMdisNacSensorModel : public MdisNacSensorModel {
  // Give linear algebra methods public accessing when using instances of this class.
  public:
    using MdisNacSensorModel::computeElevation;
    using MdisNacSensorModel::intersect;
    using MdisNacSensorModel::perpendicular;
    using MdisNacSensorModel::project;
    using MdisNacSensorModel::dot;
    using MdisNacSensorModel::magnitude;
    using MdisNacSensorModel::normalize;
};


// Set up a fixture (i.e. objects we can use throughout test)
class MdisNacSensorModelTest : public ::testing::Test {
  protected:
    // Per test-case setup and teardown (e.g. once for this MdisNacSensorModelTest)
    static void SetUpTestCase() {
      dataFile = "./data/EN1007907102M.json";
      isd = readISD(dataFile);
      // printISD(*isd);
    }
    
    static void TearDownTestCase() {
      delete isd;
      isd = NULL;
    }
    
    // Per test setup and teardown (e.g. each TEST_F)
    virtual void SetUp() {
      tolerance = 0.00001;
    }

    virtual void TearDown() {}

    static csm::Isd *isd;                // ISD converted from JSON to use for creating model.
    static std::string dataFile;         // JSON data file to be converted to ISD for testing.
    
    double tolerance;                    // Tolerance to be used for double comparison.
    MdisPlugin mdisPlugin;               // Plugin used to create a model from ISD.
    MdisNacSensorModel defaultMdisNac;   // A default constructed MdisNacSensorModel.
    TestableMdisNacSensorModel testMath; // Subclassed MdisNacSensorModel for protected methods.
};


csm::Isd *MdisNacSensorModelTest::isd = NULL;
std::string MdisNacSensorModelTest::dataFile;


/* 
 * Test imageToGround - truth extracted as follows:
 * setisis isis3
 * qview /work/projects/IAA_camera/data/EN100790102M.cub
 * F (selects "Find Tool")
 * On top toolbar, select "Find Point"
 * Type in 512.5, 512.5 for Sample/Line (ISIS3 pixel center = 1,1)
 * Click "Record Point"
 * Check "XYZ" -> { 1132.18, -1597.75, 1455.66 }
 */
TEST_F(MdisNacSensorModelTest, imageToGround1) {
  // CSM Line/Sample center = 512, 512
  csm::ImageCoord point(512.0, 512.0);
  double height = 0.0;
  
  // Create a model from the ISD so we can test a valid image.
  // Make sure the isd was read correctly.
  if (!isd) {
    FAIL() << "Could not create isd from file: " << dataFile;
  }
  std::string modelName = MdisNacSensorModel::_SENSOR_MODEL_NAME;
  csm::Model *validModel = mdisPlugin.constructModelFromISD(*isd, modelName);
  // We could static_cast, but may be hard to debug if it doesn't correctly cast.
  MdisNacSensorModel *mdisModel = dynamic_cast<MdisNacSensorModel *>(validModel);
  
  // Fatal failure if the downcast doesn't work
  if (!mdisModel) {
    FAIL() << "Could not downcast Model* to MdisNacSensorModel*.";
  }
  
  csm::EcefCoord xyz = mdisModel->imageToGround(point, height);
  double truth[] = { 1132.18*1000, -1597.75*1000, 1455.66*1000 };
  EXPECT_EQ(truth[0], xyz.x);
  EXPECT_EQ(truth[1], xyz.y);
  EXPECT_EQ(truth[2], xyz.z);
  
  // Remove the memory we took ownership of.
  delete mdisModel;
}


// Tests the getModelState() method with a default constructed MdisNacSensorModel.
TEST_F(MdisNacSensorModelTest, getModelStateDefault) {
  EXPECT_EQ(defaultMdisNac.getModelState(), std::string());
}


// Test getElevation
TEST_F(MdisNacSensorModelTest, computeElevationOnSphere) {
  // (1/4)^2 + (1/2)^2 + z^2 = 1^2; z^2 = 11/16
  double elevation = testMath.computeElevation(0.25, 0.5, sqrt(11)/4.0);
  EXPECT_EQ(0.0, elevation);
}


// Test intersect
TEST_F(MdisNacSensorModelTest, intersectTrivial) {
  std::vector<double> position { 0.0, 0.0, 1.5 };
  std::vector<double> look { 0.0, 0.0, -0.5 };
  csm::EcefCoord intersectGround = testMath.intersect(position, look, 1.0);
  EXPECT_EQ(0.0, intersectGround.x);
  EXPECT_EQ(0.0, intersectGround.y);
  EXPECT_EQ(1.0, intersectGround.z);<commit_msg>Added preliminary groundToImage test. Refactor MdisNacSensorModelTest to avoid code duplication between imageToGround and groundToImage test.<commit_after>#include <MdisPlugin.h>
#include <MdisNacSensorModel.h>
#include <IsdReader.h>

#include <csm/Isd.h>

#include <gtest/gtest.h>


/**
 * Sub-class MdisNacSensorModel to get test its protected linear algebra methods.
 * 
 * We should be testing the protected methods of MdisNacSensorModel since imageToGround
 * depends on intersect, which depends on project, etc.
 */
class TestableMdisNacSensorModel : public MdisNacSensorModel {
  // Give linear algebra methods public accessing when using instances of this class.
  public:
    using MdisNacSensorModel::computeElevation;
    using MdisNacSensorModel::intersect;
    using MdisNacSensorModel::perpendicular;
    using MdisNacSensorModel::project;
    using MdisNacSensorModel::dot;
    using MdisNacSensorModel::magnitude;
    using MdisNacSensorModel::normalize;
};


// Set up a fixture (i.e. objects we can use throughout test)
class MdisNacSensorModelTest : public ::testing::Test {
  protected:
    
    // Per test-case setup and teardown (e.g. once for this MdisNacSensorModelTest)
    static void SetUpTestCase() {
      dataFile = "./data/EN1007907102M.json";
      isd = readISD(dataFile);
      // printISD(*isd);
      
      // Make sure the isd was read correctly.
      if (isd == nullptr) {
        FAIL() << "Could not create isd from file: " << dataFile;
      }
      
      // Create a model from the ISD so we can test a valid image.
      std::string modelName = MdisNacSensorModel::_SENSOR_MODEL_NAME;
      csm::Model *validModel = mdisPlugin.constructModelFromISD(*isd, modelName);
      
      // We could static_cast, but may be hard to debug if it doesn't correctly cast.
      mdisModel = dynamic_cast<MdisNacSensorModel *>(validModel);
      std::cout << "Construction model: " << mdisModel << "\n";
      
      // Fatal failure if the downcast doesn't work
      if (mdisModel == nullptr) {
        FAIL() << "Could not downcast Model* to MdisNacSensorModel*.";
      }
    }
    
    static void TearDownTestCase() {
      delete isd;
      delete mdisModel;
    }
    
    static csm::Isd *isd;                 // ISD converted from JSON to use for creating model.
    static std::string dataFile;          // JSON data file to be converted to ISD for testing.
    static MdisPlugin mdisPlugin;         // Plugin used to create a model from ISD.
    static MdisNacSensorModel *mdisModel; // MDIS-NAC sensor model created with ISD.
    
    
    // Per test setup and teardown (e.g. each TEST_F)
    virtual void SetUp() {
      tolerance = 0.00001;
    }

    virtual void TearDown() {}
    
    double tolerance;                     // Tolerance to be used for double comparison.
    MdisNacSensorModel defaultMdisNac;    // A default constructed MdisNacSensorModel.
    TestableMdisNacSensorModel testMath;  // Subclassed MdisNacSensorModel for protected methods.
};


csm::Isd *MdisNacSensorModelTest::isd = nullptr;
std::string MdisNacSensorModelTest::dataFile;
MdisPlugin MdisNacSensorModelTest::mdisPlugin;
MdisNacSensorModel *MdisNacSensorModelTest::mdisModel = nullptr;


/* 
 * Test imageToGround - truth extracted as follows:
 * setisis isis3
 * qview /work/projects/IAA_camera/data/EN100790102M.cub
 * F (selects "Find Tool")
 * On top toolbar, select "Find Point"
 * Type in 512.5, 512.5 for Sample/Line (ISIS3 pixel center = 1,1)
 * Click "Record Point"
 * Check "XYZ" -> { 1132.18, -1597.75, 1455.66 }
 */
TEST_F(MdisNacSensorModelTest, imageToGround1) {
  // CSM Line/Sample center = 512, 512
  csm::ImageCoord point(512.0, 512.0);
  double height = 0.0;  
  csm::EcefCoord xyz = mdisModel->imageToGround(point, height);
  double truth[] = { 1132.18*1000, -1597.75*1000, 1455.66*1000 };
  EXPECT_EQ(truth[0], xyz.x);
  EXPECT_EQ(truth[1], xyz.y);
  EXPECT_EQ(truth[2], xyz.z);
}


// Test groundToImage
TEST_F(MdisNacSensorModelTest, groundToImage1) {
  double x = 1132.18*1000;
  double y = -1597.75*1000;
  double z = 1455.66*1000;
  csm::EcefCoord xyz(x, y, z);
  csm::ImageCoord pt = mdisModel->groundToImage(xyz);
  EXPECT_EQ(512.0, pt.line);
  EXPECT_EQ(512.0, pt.samp);
}


// Tests the getModelState() method with a default constructed MdisNacSensorModel.
TEST_F(MdisNacSensorModelTest, getModelStateDefault) {
  EXPECT_EQ(defaultMdisNac.getModelState(), std::string());
}


// Test getElevation
TEST_F(MdisNacSensorModelTest, computeElevationOnSphere) {
  // (1/4)^2 + (1/2)^2 + z^2 = 1^2; z^2 = 11/16
  double elevation = testMath.computeElevation(0.25, 0.5, sqrt(11)/4.0);
  EXPECT_EQ(0.0, elevation);
}


// Test intersect
TEST_F(MdisNacSensorModelTest, intersectTrivial) {
  std::vector<double> position { 0.0, 0.0, 1.5 };
  std::vector<double> look { 0.0, 0.0, -0.5 };
  csm::EcefCoord intersectGround = testMath.intersect(position, look, 1.0);
  EXPECT_EQ(0.0, intersectGround.x);
  EXPECT_EQ(0.0, intersectGround.y);
  EXPECT_EQ(1.0, intersectGround.z);
{'fraction_non_alphanumeric': 0.11257639112254744, 'fraction_numerical': 0.03634609199099389, 'mean_word_length': 3.536964980544747, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '105319', 'n_tokens_mistral': 3423, 'n_tokens_neox': 3226, 'n_words': 829}