Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
LoadAscii2Test.h 17.94 KiB
#ifndef LOADASCIITEST_H_
#define LOADASCIITEST_H_

#include "cxxtest/TestSuite.h"
#include "MantidDataHandling/LoadAscii2.h"
#include "MantidDataHandling/SaveAscii2.h"
#include "MantidAPI/AnalysisDataService.h"
#include "MantidDataObjects/Workspace2D.h"
#include <Poco/File.h>
#include <fstream>

using namespace Mantid::API;
using namespace Mantid::DataHandling;
using namespace Mantid::Kernel;
using namespace Mantid::DataObjects;

class LoadAscii2Test : public CxxTest::TestSuite {
public:
  static LoadAscii2Test *createSuite() { return new LoadAscii2Test(); }
  static void destroySuite(LoadAscii2Test *suite) { delete suite; }

  LoadAscii2Test() {
    m_filename = "LoadAscii2Test";
    m_ext = ".txt";
    m_testno = 0;
  }

  ~LoadAscii2Test() {}

  void testProperties() {
    m_testno++;
    LoadAscii2 testLoad;
    TS_ASSERT_EQUALS("LoadAscii", testLoad.name());
    TS_ASSERT_EQUALS(2, testLoad.version());
    TS_ASSERT_EQUALS("DataHandling\\Text", testLoad.category());
  }
  // the Poco::File.remove() is always in a TS_ASERT as i need to make sure the
  // loader has released the file.
  void testConfidence() {
    m_testno++;
    LoadAscii2 testLoad;
    testLoad.initialize();
    m_abspath = writeTestFile(3);
    // descriptor keeps an open handle until destructor call, so the destructor
    // must run before i can remove it
    auto *descriptor = new FileDescriptor(m_abspath);
    TS_ASSERT_EQUALS(10, testLoad.confidence(*descriptor));
    delete descriptor;
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Three_Column_Example_With_No_Header() {
    m_testno++;
    m_abspath = writeTestFile(3, false);
    runTest(3);
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Three_Column_With_Header_Info() {
    m_testno++;
    m_abspath = writeTestFile(3);
    runTest(3);
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Two_Column_Example_With_No_Header() {
    m_testno++;
    m_abspath = writeTestFile(2, false);
    runTest(2);
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Two_Column_With_Header_Info() {
    m_testno++;
    m_abspath = writeTestFile(2);
    runTest(2);
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Four_Column_Example_With_No_Header() {
    m_testno++;
    m_abspath = writeTestFile(4, false);
    runTest(4);
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Four_Column_Example_With_HeaderInfo() {
    m_testno++;
    m_abspath = writeTestFile(4);
    runTest(4);
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Four_Column_With_HeaderInfo_CommentChange() {
    m_testno++;
    m_abspath = writeTestFile(4, true, "~");
    runTest(4, false, "~");
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Four_Column_With_HeaderInfo_NonScientific() {
    m_testno++;
    m_abspath = writeTestFile(4, true, "#", false, 7);
    runTest(4);
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Four_Column_With_Different_Separator() {
    m_testno++;
    m_abspath = writeTestFile(4, true, "#", true, 6, "Space");
    runTest(4, true, "#", "Space");
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Custom_Separators() {
    m_testno++;
    m_abspath = writeTestFile(4, true, "#", true, 6, "UserDefined", "~");
    runTest(4, false, "#", "UserDefined", false, "~");
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Spacing_Around_Separators() {
    m_testno++;
    m_abspath = writeTestFile(4, true, "#", true, 6, "UserDefined",
                              " , "); // space comma space
    // this should work as the load will look for commas and strip out excess
    // spaces
    runTest(4);
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_Double_Spacing_Separators() {
    m_testno++;
    m_abspath = writeTestFile(4, true, "#", true, 6, "UserDefined",
                              "  "); // double space
    // this should work as the load will strip out excess spaces
    runTest(4, true, "#", "Space");
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }
  void test_fail_five_columns() {
    m_testno++;
    std::ofstream file(getTestFileName().c_str());
    m_abspath = getAbsPath();
    file << std::scientific;
    file << "# X , Y, E, DX, Z" << std::endl;
    for (int i = 0; i < 5; i++) {
      file << i << std::endl;
      for (int j = 0; j < 4; j++) {
        file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
             << "," << 1 << "," << 0 << ","
             << (i + 5) * (6. + 3. * (1.7 * j / 0.8)) << std::endl;
      }
    }
    file.unsetf(std::ios_base::floatfield);
    file.close();
    runTest(4, false, "#", "CSV", true); // cols doesn't matter here
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_fail_one_column() {
    m_testno++;
    std::ofstream file(getTestFileName().c_str());
    m_abspath = getAbsPath();
    file << std::scientific;
    file << "# X" << std::endl;
    for (int i = 0; i < 5; i++) {
      file << i << std::endl;
      for (int j = 0; j < 4; j++) {
        file << 1.5 * j / 0.9 << std::endl;
      }
    }
    file.unsetf(std::ios_base::floatfield);
    file.close();
    runTest(1, false, "#", "CSV", true); // cols doesn't matter here
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_fail_mismatching_bins() {
    m_testno++;
    std::ofstream file(getTestFileName().c_str());
    m_abspath = getAbsPath();
    file << std::scientific;
    file << "# X , Y, E, DX" << std::endl;
    for (int i = 0; i < 5; i++) {
      file << i << std::endl;
      for (int j = 0; j < 4; j++) {
        if (!(i == 3 && j == 2)) {
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << "," << 1 << "," << 0 << std::endl;
        }
      }
    }
    file.unsetf(std::ios_base::floatfield);
    file.close();
    runTest(4, false, "#", "CSV", true); // cols doesn't matter here
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_fail_mismatching_columns() {
    m_testno++;
    std::ofstream file(getTestFileName().c_str());
    m_abspath = getAbsPath();
    file << std::scientific;
    file << "# X , Y, E, DX" << std::endl;
    for (int i = 0; i < 5; i++) {
      file << i << std::endl;
      for (int j = 0; j < 4; j++) {
        if (!(i == 3 && j == 2)) {
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << "," << 1 << "," << 0 << std::endl;
        } else {
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << "," << 1 << std::endl;
        }
      }
    }
    file.unsetf(std::ios_base::floatfield);
    file.close();
    runTest(4, false, "#", "CSV", true); // cols doesn't matter here
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_fail_line_start_letter() {
    m_testno++;
    std::ofstream file(getTestFileName().c_str());
    m_abspath = getAbsPath();
    file << std::scientific;
    file << "# X , Y, E, DX" << std::endl;
    for (int i = 0; i < 5; i++) {
      file << i << std::endl;
      for (int j = 0; j < 4; j++) {
        if (!(i == 3 && j == 2)) {
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << "," << 1 << "," << 0 << std::endl;
        } else {
          // used e to make sure it'd not get mistaken for a scientific index
          file << "e" << 1.5 * j / 0.9 << ","
               << (i + 1) * (2. + 4. * (1.5 * j / 0.9)) << "," << 1 << "," << 0
               << std::endl;
        }
      }
    }
    file.unsetf(std::ios_base::floatfield);
    file.close();
    runTest(4, false, "#", "CSV", true); // cols doesn't matter here
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_fail_line_start_noncomment_symbol() {
    m_testno++;
    std::ofstream file(getTestFileName().c_str());
    m_abspath = getAbsPath();
    file << std::scientific;
    file << "# X , Y, E, DX" << std::endl;
    for (int i = 0; i < 5; i++) {
      file << i << std::endl;
      for (int j = 0; j < 4; j++) {
        if (!(i == 3 && j == 2)) {
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << "," << 1 << "," << 0 << std::endl;
        } else {
          file << "@" << 1.5 * j / 0.9 << ","
               << (i + 1) * (2. + 4. * (1.5 * j / 0.9)) << "," << 1 << "," << 0
               << std::endl;
        }
      }
    }
    file.unsetf(std::ios_base::floatfield);
    file.close();
    runTest(4, false, "#", "CSV", true); // cols doesn't matter here
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_fail_line_mixed_letter_number() {
    m_testno++;
    std::ofstream file(getTestFileName().c_str());
    m_abspath = getAbsPath();
    file << std::scientific;
    file << "# X , Y, E, DX" << std::endl;
    for (int i = 0; i < 5; i++) {
      file << i << std::endl;
      for (int j = 0; j < 4; j++) {
        if (!(i == 3 && j == 2)) {
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << "," << 1 << "," << 0 << std::endl;
        } else {
          // used e to make sure it'd not get mistaken for a scientific index
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << "e"
               << "," << 1 << "," << 0 << std::endl;
        }
      }
    }
    file.unsetf(std::ios_base::floatfield);
    file.close();
    runTest(4, false, "#", "CSV", true); // cols doesn't matter here
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_fail_line_mixed_symbol_number() {
    m_testno++;
    std::ofstream file(getTestFileName().c_str());
    m_abspath = getAbsPath();
    file << std::scientific;
    file << "# X , Y, E, DX" << std::endl;
    for (int i = 0; i < 5; i++) {
      file << i << std::endl;
      for (int j = 0; j < 4; j++) {
        if (!(i == 3 && j == 2)) {
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << "," << 1 << "," << 0 << std::endl;
        } else {
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << "/"
               << "," << 1 << "," << 0 << std::endl;
        }
      }
    }
    file.unsetf(std::ios_base::floatfield);
    file.close();
    runTest(4, false, "#", "CSV", true); // cols doesn't matter here
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

  void test_fail_spectra_ID_inclusion_inconisitant() {
    m_testno++;
    std::ofstream file(getTestFileName().c_str());
    m_abspath = getAbsPath();

    file << std::scientific;
    file << "# X , Y, E, DX" << std::endl;
    for (int i = 0; i < 5; i++) {
      if (i != 3) {
        file << i << std::endl;
      } else {
        file << std::endl;
      }
      for (int j = 0; j < 4; j++) {
        file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
             << "," << 1 << "," << 0 << std::endl;
      }
    }
    file.unsetf(std::ios_base::floatfield);
    file.close();
    runTest(4, false, "#", "CSV", true); // cols doesn't matter here
    TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove());
  }

private:
  const std::string getTestFileName() const {
    return m_filename + boost::lexical_cast<std::string>(m_testno) + m_ext;
  }
  std::string getAbsPath() {
    SaveAscii2 save;
    save.initialize();
    save.setPropertyValue("Filename", getTestFileName());
    return save.getPropertyValue("Filename");
  }
  // Write the test file
  std::string writeTestFile(const int cols, const bool header = true,
                            const std::string &comment = "#",
                            const bool scientific = true,
                            const int precision = -1,
                            const std::string &sep = "CSV",
                            const std::string &custsep = "") {
    SaveAscii2 save;
    save.initialize();
    save.setPropertyValue("Filename", getTestFileName());
    if (cols < 3) {
      // saveascii2 doens't save 2 column files it has to be made manually
      std::ofstream file(getTestFileName().c_str());
      if (scientific) {
        file << std::scientific;
      }
      if (header) {
        file << comment << "X , Y" << std::endl;
      }
      for (int i = 0; i < 5; i++) {
        file << i << std::endl;
        for (int j = 0; j < 4; j++) {
          file << 1.5 * j / 0.9 << "," << (i + 1) * (2. + 4. * (1.5 * j / 0.9))
               << std::endl;
        }
      }
      file.unsetf(std::ios_base::floatfield);
      file.close();
    } else {
      Mantid::DataObjects::Workspace2D_sptr wsToSave =
          boost::dynamic_pointer_cast<Mantid::DataObjects::Workspace2D>(
              WorkspaceFactory::Instance().create("Workspace2D", 5, 4, 4));
      for (int i = 0; i < 5; i++) {
        std::vector<double> &X = wsToSave->dataX(i);
        std::vector<double> &Y = wsToSave->dataY(i);
        std::vector<double> &E = wsToSave->dataE(i);
        std::vector<double> &DX = wsToSave->dataDx(i);
        for (int j = 0; j < 4; j++) {
          X[j] = 1.5 * j / 0.9;
          Y[j] = (i + 1) * (2. + 4. * X[j]);
          E[j] = 1.;
          if (cols == 4) {
            DX[j] = 1.;
          }
        }
      }
      const std::string name = "SaveAsciiWS";
      AnalysisDataService::Instance().add(name, wsToSave);

      save.initialize();
      save.isInitialized();
      if (precision > -1) {
        save.setPropertyValue("Precision",
                              boost::lexical_cast<std::string>(precision));
      }
      save.setPropertyValue("InputWorkspace", name);
      save.setPropertyValue("CommentIndicator", comment);
      save.setPropertyValue("ScientificFormat",
                            boost::lexical_cast<std::string>(scientific));
      save.setPropertyValue("ColumnHeader",
                            boost::lexical_cast<std::string>(header));
      save.setPropertyValue("WriteXError",
                            boost::lexical_cast<std::string>(cols == 4));
      save.setPropertyValue("Separator", sep);
      save.setPropertyValue("CustomSeparator", custsep);
      save.execute();

      AnalysisDataService::Instance().remove(name);
    }
    return save.getPropertyValue("Filename");
  }

  Mantid::API::MatrixWorkspace_sptr
  runTest(const int cols, const bool dataCheck = true,
          const std::string &comment = "#", const std::string &sep = "CSV",
          const bool execThrows = false, const std::string &custsep = "") {
    using Mantid::DataHandling::LoadAscii2;
    using namespace Mantid::API;

    LoadAscii2 loader;
    loader.initialize();
    loader.setRethrows(true);
    const std::string outputName(getTestFileName());
    TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("Filename", m_abspath));
    TS_ASSERT_THROWS_NOTHING(
        loader.setPropertyValue("OutputWorkspace", outputName));
    TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("Separator", sep));
    TS_ASSERT_THROWS_NOTHING(
        loader.setPropertyValue("CustomSeparator", custsep));
    TS_ASSERT_THROWS_NOTHING(
        loader.setPropertyValue("CommentIndicator", comment));

    if (execThrows) {
      TS_ASSERT_THROWS_ANYTHING(loader.execute());
    } else {
      TS_ASSERT_THROWS_NOTHING(loader.execute());

      TS_ASSERT_EQUALS(loader.isExecuted(), true);

      // Check the workspace
      AnalysisDataServiceImpl &dataStore = AnalysisDataService::Instance();
      if (dataStore.doesExist(outputName)) {
        TS_ASSERT_EQUALS(dataStore.doesExist(outputName), true);
        Workspace_sptr output;
        TS_ASSERT_THROWS_NOTHING(output = dataStore.retrieve(outputName));
        MatrixWorkspace_sptr outputWS =
            boost::dynamic_pointer_cast<MatrixWorkspace>(output);
        if (outputWS) {
          if (dataCheck) {
            checkData(outputWS, cols);
            // Test output
            TS_ASSERT_EQUALS(outputWS->getAxis(0)->unit()->caption(), "Energy");
            TS_ASSERT_EQUALS(outputWS->getAxis(0)->unit()->label(), "meV");
          }
          // Check if filename is saved
          TS_ASSERT_EQUALS(loader.getPropertyValue("Filename"),
                           outputWS->run().getProperty("Filename")->value());
        } else {
          TS_FAIL(outputName + " does not exist.");
        }
        dataStore.remove(outputName);
        return outputWS;
      } else {
        TS_FAIL("Cannot retrieve output workspace");
      }
    }
    MatrixWorkspace_sptr outputWS;
    return outputWS;
  }

  void checkData(const Mantid::API::MatrixWorkspace_sptr outputWS,
                 const int cols) {
    TS_ASSERT_EQUALS(outputWS->getNumberHistograms(), 5);
    TS_ASSERT_EQUALS(outputWS->blocksize(), 4);

    TS_ASSERT_DELTA(outputWS->readX(0)[0], 0, 1e-6);
    TS_ASSERT_DELTA(outputWS->readY(0)[0], 2, 1e-6);

    TS_ASSERT_DELTA(outputWS->readX(0)[1], 1.666667, 1e-6);
    TS_ASSERT_DELTA(outputWS->readY(0)[1], 8.666667, 1e-6);

    TS_ASSERT_DELTA(outputWS->readX(1)[2], 3.333333, 1e-6);
    TS_ASSERT_DELTA(outputWS->readY(1)[2], 30.66667, 1e-6);

    TS_ASSERT_DELTA(outputWS->readX(3)[3], 5, 1e-6);
    TS_ASSERT_DELTA(outputWS->readY(3)[3], 88, 1e-6);
    if (cols == 3 || cols == 4) {
      TS_ASSERT_DELTA(outputWS->readE(0)[0], 1, 1e-6);

      TS_ASSERT_DELTA(outputWS->readE(0)[1], 1, 1e-6);

      TS_ASSERT_DELTA(outputWS->readE(1)[2], 1, 1e-6);

      TS_ASSERT_DELTA(outputWS->readE(3)[3], 1, 1e-6);
    } else {
      TS_ASSERT_DELTA(outputWS->readE(0)[0], 0, 1e-6);

      TS_ASSERT_DELTA(outputWS->readE(0)[1], 0, 1e-6);

      TS_ASSERT_DELTA(outputWS->readE(1)[2], 0, 1e-6);

      TS_ASSERT_DELTA(outputWS->readE(3)[3], 0, 1e-6);
    }
    if (cols == 4) {
      TS_ASSERT_DELTA(outputWS->readDx(0)[0], 1, 1e-6);

      TS_ASSERT_DELTA(outputWS->readDx(0)[1], 1, 1e-6);

      TS_ASSERT_DELTA(outputWS->readDx(1)[2], 1, 1e-6);

      TS_ASSERT_DELTA(outputWS->readDx(3)[3], 1, 1e-6);
    }
  }
  std::string m_filename;
  std::string m_abspath;
  std::string m_ext;
  size_t m_testno;
};

#endif // LOADASCIITEST_H_