// ./tests/catch2-tests [section] -s


/////////////////////// Qt includes
#include <QDebug>
#include <QString>
#include <QStringList>
#include <QDir>


/////////////////////// IsoSpec
#include <IsoSpec++/isoSpec++.h>
#include <IsoSpec++/element_tables.h>


/////////////////////// Catch2 includes
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>


/////////////////////// Local includes
#include "tests-config.h"
#include "TestUtils.hpp"
#include "MsXpS/libXpertMassCore/Modif.hpp"

namespace MsXpS
{
namespace libXpertMassCore
{

TestUtils test_utils_1_letter_modif("protein-1-letter", 1);

ErrorList error_list;

bool ok;

int mdf_element_index      = 0;
int name_element_index     = 1;
int name_text_index        = 2;
int formula_element_index  = 3;
int formula_text_index     = 4;
int targets_element_index  = 5;
int targets_text_index     = 6;
int maxcount_element_index = 7;
int maxcount_text_index    = 8;


QStringList dom_strings{"mdf",
                        "name",
                        "Acetylation",
                        "formula",
                        "-H2O+CH3COOH",
                        "targets",
                        "K",
                        "maxcount",
                        "1"};

SCENARIO("Construction of a Modif starting from empty", "[Modif]")
{
  WHEN("A Modif is created empty")
  {
    Modif modif;

    THEN("It is invalid and does not validate successfully")
    {
      REQUIRE_FALSE(modif.isValid());

      error_list.clear();
      REQUIRE_FALSE(modif.validate(&error_list));
    }

    qDebug() << "HERE";

    THEN(
      "It is not possible to assess if it is known to the polymer chemistry "
      "definition")
    {
      REQUIRE(modif.isKnownByNameInPolChemDef() ==
              Enums::PolChemDefEntityStatus::POL_CHEM_DEF_NOT_AVAILABLE);
    }

    AND_WHEN("Setting the PolChemDef")
    {
      modif.setPolChemDefCstSPtr(test_utils_1_letter_modif.msp_polChemDef);

      THEN(
        "It must be set but the Modif is still invalid and does not validate "
        "successfully")
      {
        REQUIRE(modif.getPolChemDefCstSPtr() ==
                test_utils_1_letter_modif.msp_polChemDef);

        REQUIRE_FALSE(modif.isValid());

        error_list.clear();
        REQUIRE_FALSE(modif.validate(&error_list));
      }

      AND_WHEN("Setting an empty name")
      {
        modif.setName("");

        THEN(
          "It must be set but the Modif is still invalid and does not validate "
          "successfully")
        {
          REQUIRE(modif.getName().toStdString() == "");
          REQUIRE_FALSE(modif.isValid());

          error_list.clear();
          REQUIRE_FALSE(modif.validate(&error_list));
        }
      }

      AND_WHEN("Setting the name")
      {
        REQUIRE(modif.getPolChemDefCstSPtr() ==
                test_utils_1_letter_modif.msp_polChemDef);

        modif.setName("Acetylation");

        THEN(
          "It must be set but the Modif is still invalid and does not validate "
          "successfully")
        {
          REQUIRE(modif.getName().toStdString() == "Acetylation");
          REQUIRE_FALSE(modif.isValid());

          error_list.clear();
          REQUIRE_FALSE(modif.validate(&error_list));
        }

        AND_WHEN("Setting a bad formula with title")
        {
          modif.setFormula("\"The title\"-h2O+cH3COOH");

          THEN(
            "It must be set and the Modif is still invalid and does not "
            "validate "
            "successfully")
          {
            REQUIRE(modif.getFormula().toStdString() ==
                    "\"The title\"-h2O+cH3COOH");
            REQUIRE(modif.formula(/*with_title*/ false).toStdString() ==
                    "-h2O+cH3COOH");

            REQUIRE_FALSE(modif.isValid());

            error_list.clear();
            REQUIRE_FALSE(modif.validate(&error_list));
          }
        }

        AND_WHEN("Setting a valid formula with title")
        {
          REQUIRE(modif.getPolChemDefCstSPtr() ==
                  test_utils_1_letter_modif.msp_polChemDef);

          modif.setFormula("\"The title\"-H2O+CH3COOH");

          THEN(
            "It must be set and now the Modif is not valid (targets not "
            "defined) and does not validate successfully")
          {
            qDebug() << "The modif:" << modif.toString();
            REQUIRE(modif.getFormula().toStdString() ==
                    "\"The title\"-H2O+CH3COOH");
            REQUIRE(modif.formula(/*with_title*/ false).toStdString() ==
                    "-H2O+CH3COOH");

            REQUIRE_FALSE(modif.isValid());

            error_list.clear();
            REQUIRE_FALSE(modif.validate(&error_list));
          }

          AND_WHEN("Setting an erroneous targets string")
          {
            QString failing_targets_string("ST*Y!");
            modif.setTargets(failing_targets_string);

            THEN("The Modif is not valid and does not validate successfully")
            {
              qDebug() << "The modif:" << modif.toString();
              modif.validateTargets(/*simplify*/ true, ok);
              REQUIRE_FALSE(ok);
              modif.validateTargets(
                failing_targets_string, /*simplify*/ true, ok);
              REQUIRE_FALSE(ok);

              REQUIRE_FALSE(modif.isValid());

              error_list.clear();
              REQUIRE_FALSE(modif.validate(&error_list));
            }
          }

          AND_WHEN("Setting a correct targets string")
          {
            QString targets_string("K;R;M;C");
            modif.setTargets(targets_string);

            THEN(
              "The Modif is not valid (max count not defined) and does not "
              "validate successfully")
            {
              qDebug() << "The modif:" << modif.toString();
              modif.validateTargets(/*simplify*/ true, ok);
              REQUIRE(ok);
              modif.validateTargets(targets_string, /*simplify*/ true, ok);
              REQUIRE(ok);

              REQUIRE_FALSE(modif.isValid());

              error_list.clear();
              REQUIRE_FALSE(modif.validate(&error_list));
            }

            AND_WHEN("Setting an erroneous max count value")
            {
              modif.setMaxCount(0);

              THEN(
                "The Modif is not valid anymore and does not validate "
                "successfully")
              {
                qDebug() << "The modif:" << modif.toString();
                REQUIRE_FALSE(modif.isValid());

                error_list.clear();
                REQUIRE_FALSE(modif.validate(&error_list));
              }

              AND_WHEN("Setting a correct max count value")
              {
                modif.setMaxCount(2);

                THEN(
                  "The Modif is valid and does validate "
                  "successfully")
                {
                  qDebug() << "The modif:" << modif.toString();

                  REQUIRE(modif.isValid());

                  error_list.clear();
                  REQUIRE(modif.validate(&error_list));
                }
              }
            }
          }
        }
      }
    }
  }
}

SCENARIO(
  "Construction of a Modif starting from valid PolChemDef, name and formula",
  "[Modif]")
{
  WHEN("A Modif is created with PolChemDef,  name and formula")
  {
    Modif modif(test_utils_1_letter_modif.msp_polChemDef,
                "Acetylation",
                "\"The title\"-H2O+CH3COOH");

    THEN(
      "The Modif is not valid and does not validate successfully (targets and "
      "max count not defined)")
    {
      error_list.clear();
      REQUIRE_FALSE(modif.validate(&error_list));

      REQUIRE_FALSE(modif.isValid());

      AND_THEN("Calculating the masses should work nonetheless")
      {
        modif.calculateMasses(nullptr);

        double mono = 0;
        double avg  = 0;

        modif.accountMasses(mono, avg, /*times*/ 1);

        REQUIRE_THAT(mono,
                     Catch::Matchers::WithinAbs(42.0105646847, 0.0000000001));
        REQUIRE_THAT(avg,
                     Catch::Matchers::WithinAbs(42.0369401545, 0.0000000001));
      }
    }

    AND_WHEN("Setting proper targets and max count")
    {
      modif.setTargets("M;C");
      modif.setMaxCount(3);

      THEN("It is valid and does validate successfully")
      {
        REQUIRE(modif.isValid());

        error_list.clear();
        REQUIRE(modif.validate(&error_list));
      }
    }
  }
}

SCENARIO("Setting bad values with setters invalidates a valid Modif", "[Modif]")
{

  GIVEN(
    "A Modif created with PolChemDef, name and formula, and targets and max "
    "count set")
  {
    Modif modif(test_utils_1_letter_modif.msp_polChemDef,
                "Acetylation",
                "\"The title\"-H2O+CH3COOH");
    modif.setTargets("K;R");
    modif.setMaxCount(2);

    qDebug() << "At this point,  the modif:" << modif.toString();

    THEN(
      "The Modif is valid and validates successfully with masses properly "
      "calculated")
    {
      qDebug() << "BEFORE The modif: " << modif.toString();
      REQUIRE(modif.isValid());
      qDebug() << "AFTER The modif: " << modif.toString();

      error_list.clear();
      REQUIRE(modif.validate(&error_list));

      modif.calculateMasses(nullptr);

      double mono = 0;
      double avg  = 0;

      modif.accountMasses(mono, avg, /*times*/ 1);

      REQUIRE_THAT(mono,
                   Catch::Matchers::WithinAbs(42.0105646847, 0.0000000001));
      REQUIRE_THAT(avg,
                   Catch::Matchers::WithinAbs(42.0369401545, 0.0000000001));
    }

    WHEN("Setting an empty name")
    {
      modif.setName("");

      THEN("It is no more valid and does not validate successfully")
      {
        REQUIRE_FALSE(modif.isValid());

        error_list.clear();
        REQUIRE_FALSE(modif.validate(&error_list));
      }

      modif.setName("Acetylation");
    }
  }
}

SCENARIO("A Modif can be searched for in the PolChemDef", "[Modif]")
{
  WHEN("A Modif is created with PolChemDef,  existing name and formula")
  {
    Modif modif(test_utils_1_letter_modif.msp_polChemDef,
                "Acetylation",
                "\"The title\"-H2O+CH3COOH");

    THEN(
      "The Modif is not valid and does not validate successfully (targets and "
      "max count not defined) althought the masses are properly calculated")
    {
      error_list.clear();
      REQUIRE_FALSE(modif.validate(&error_list));
      REQUIRE_FALSE(modif.isValid());

      modif.calculateMasses(nullptr);

      double mono = 0;
      double avg  = 0;

      REQUIRE(modif.accountMasses(mono, avg, /*times*/ 1) == modif);

      REQUIRE_THAT(mono,
                   Catch::Matchers::WithinAbs(42.0105646847, 0.0000000001));
      REQUIRE_THAT(avg,
                   Catch::Matchers::WithinAbs(42.0369401545, 0.0000000001));

      mono = 0;
      avg  = 0;

      REQUIRE(modif.accountMasses(&mono, &avg, /*times*/ 1) == modif);

      REQUIRE_THAT(mono,
                   Catch::Matchers::WithinAbs(42.0105646847, 0.0000000001));
      REQUIRE_THAT(avg,
                   Catch::Matchers::WithinAbs(42.0369401545, 0.0000000001));

      mono = 0;
      avg  = 0;

      REQUIRE(modif.accountMasses(nullptr, nullptr, /*times*/ 1) == modif);

      REQUIRE_THAT(mono, Catch::Matchers::WithinAbs(0, 0.0000000001));
      REQUIRE_THAT(avg, Catch::Matchers::WithinAbs(0, 0.0000000001));
    }

    THEN("Calculating masses proactively should work")
    {
      REQUIRE(
        modif ==
        modif.calculateMasses(
          ok,
          test_utils_1_letter_modif.msp_polChemDef->getIsotopicDataCstSPtr()));
      REQUIRE(modif == modif.calculateMasses(ok, nullptr));
      REQUIRE(modif.calculateMasses(nullptr));
    }

    THEN("The Modif in the PolChemDef can be retrieved by member name")
    {
      ModifCstSPtr modif_csp = test_utils_1_letter_modif.msp_polChemDef->getModifCstSPtrByName(modif.getName());

      REQUIRE(modif_csp != nullptr);
      REQUIRE(modif_csp->getName().toStdString() ==  "Acetylation");
    }

    THEN(
      "The Modif in the PolChemDef can be retrieved by explicit name")
    {
      ModifCstSPtr modif_csp = test_utils_1_letter_modif.msp_polChemDef->getModifCstSPtrByName(modif.getName());

      REQUIRE(modif_csp != nullptr);
      REQUIRE(modif_csp->getName().toStdString() ==  "Acetylation");

      modif_csp = test_utils_1_letter_modif.msp_polChemDef->getModifCstSPtrByName("");
      REQUIRE(
        modif_csp == nullptr);
    }

    THEN("The Modif in the PolChemDef can checked by name")
    {
      REQUIRE(modif.isKnownByNameInPolChemDef() == Enums::PolChemDefEntityStatus::ENTITY_KNOWN);
    }
  }

  WHEN(
    "A Modif is created with PolChemDef,  inexisting name, correct formula,  "
    "targets and max count")
  {
    Modif modif(test_utils_1_letter_modif.msp_polChemDef,
                "Notacetylation",
                "\"The title\"-H2O+CH3COOH");
    modif.setTargets("M;C");
    modif.setMaxCount(2);

    THEN(
      "The Modif is valid and validates successfully with masses properly "
      "calculated")
    {
      error_list.clear();
      REQUIRE(modif.validate(&error_list));
      REQUIRE(modif.isValid());

      modif.calculateMasses(nullptr);

      double mono = 0;
      double avg  = 0;

      modif.accountMasses(mono, avg, /*times*/ 1);

      REQUIRE_THAT(mono,
                   Catch::Matchers::WithinAbs(42.0105646847, 0.0000000001));
      REQUIRE_THAT(avg,
                   Catch::Matchers::WithinAbs(42.0369401545, 0.0000000001));
    }

    THEN("Calculating masses proactively should work")
    {
      REQUIRE(
        modif ==
        modif.calculateMasses(
          ok,
          test_utils_1_letter_modif.msp_polChemDef->getIsotopicDataCstSPtr()));
    }

    THEN("The Modif in the PolChemDef cannot be retrieved by member name")
    {
      ModifCstSPtr modif_csp = test_utils_1_letter_modif.msp_polChemDef->getModifCstSPtrByName(modif.getName());
      REQUIRE(modif_csp == nullptr);

      modif_csp = modif.getFromPolChemDefByName();
      REQUIRE(modif_csp == nullptr);

      REQUIRE(modif.isKnownByNameInPolChemDef() ==
              Enums::PolChemDefEntityStatus::ENTITY_NOT_KNOWN);
    }
  }
}

SCENARIO("Construction of a Modif with the copy constructor", "[Modif]")
{
  WHEN("A Modif is created with PolChemDef,  name and formula")
  {
    Modif modif(test_utils_1_letter_modif.msp_polChemDef,
                "Acetylation",
                "\"The title\"-H2O+CH3COOH");
    modif.setTargets("M;C");
    modif.setMaxCount(2);

    THEN(
      "The Modif is valid and validates successfully with masses properly "
      "calculated")
    {
      REQUIRE(modif.isValid());

      error_list.clear();
      REQUIRE(modif.validate(&error_list));

      double mono = 0;
      double avg  = 0;

      modif.accountMasses(mono, avg, /*times*/ 1);

      REQUIRE_THAT(modif.getMass(Enums::MassType::MONO),
                   Catch::Matchers::WithinAbs(42.0105646847, 0.0000000001));
      REQUIRE_THAT(modif.getMass(Enums::MassType::AVG),
                   Catch::Matchers::WithinAbs(42.0369401545, 0.0000000001));

      REQUIRE_THAT(mono,
                   Catch::Matchers::WithinAbs(42.0105646847, 0.0000000001));
      REQUIRE_THAT(avg,
                   Catch::Matchers::WithinAbs(42.0369401545, 0.0000000001));
    }

    AND_WHEN("Another Modif is copy-constructed")
    {
      Modif new_modif(modif);

      THEN("It should be identical to the previous one")
      {
        REQUIRE(new_modif.getName().toStdString() ==
                modif.getName().toStdString());
        REQUIRE(new_modif.getFormula().toStdString() ==
                modif.getFormula().toStdString());
        REQUIRE(new_modif.formula(/*with_title*/ false).toStdString() ==
                modif.formula(/*with_title*/ false).toStdString());
        REQUIRE(new_modif.getTargets().toStdString() ==
                modif.getTargets().toStdString());
        REQUIRE(new_modif.getMaxCount() == modif.getMaxCount());
      }

      THEN("The equality operator should work fine")
      {
        REQUIRE(new_modif == modif);
        REQUIRE_FALSE(new_modif != modif);
      }
    }

    AND_WHEN(
      "Another Modif is initialized using it with the assignment operator=()")
    {
      Modif another_new_modif;
      another_new_modif = modif;

      THEN("It should be identical to the previous one")
      {
        REQUIRE(another_new_modif.getName().toStdString() ==
                modif.getName().toStdString());
        REQUIRE(another_new_modif.getFormula().toStdString() ==
                modif.getFormula().toStdString());
        REQUIRE(another_new_modif.formula(/*with_title*/ false).toStdString() ==
                modif.formula(/*with_title*/ false).toStdString());
        REQUIRE(another_new_modif.getTargets().toStdString() ==
                modif.getTargets().toStdString());
        REQUIRE(another_new_modif.getMaxCount() == modif.getMaxCount());
      }

      THEN("Assigning a Modif to itself should return itself.")
      {
        REQUIRE((another_new_modif = another_new_modif) == another_new_modif);
      }

      THEN("The equality operator should work fine")
      {
        REQUIRE(another_new_modif == modif);
        REQUIRE_FALSE(another_new_modif != modif);
        REQUIRE(another_new_modif == another_new_modif);
        REQUIRE_FALSE(another_new_modif != another_new_modif);
      }
    }
  }
}

SCENARIO("A Modif can be checked for its targets", "[Modif]")
{

  WHEN(
    "A Modif is created with PolChemDef,  name and formula,  then targets are "
    "set using setter")
  {
    Modif modif(test_utils_1_letter_modif.msp_polChemDef,
                "Acetylation",
                "\"The title\"-H2O+CH3COOH");
    modif.setTargets("M;C");
    modif.setMaxCount(2);

    THEN("The Modif is checked")
    {
      REQUIRE(modif.isValid());

      error_list.clear();
      REQUIRE(modif.validate(&error_list));

      REQUIRE(modif.doesTargetMonomer("M"));
      REQUIRE(modif.doesTargetMonomer("C"));
      REQUIRE_FALSE(modif.doesTargetMonomer("A"));
    }

    AND_WHEN("Set targets '*'")
    {
      modif.setTargets("*");

      THEN("All codes should be targeted")
      {
        REQUIRE(modif.doesTargetMonomer("M"));
        REQUIRE(modif.doesTargetMonomer("C"));
        REQUIRE(modif.doesTargetMonomer("A"));
      }
    }

    AND_WHEN("Set targets '!'")
    {
      modif.setTargets("!");

      THEN("No code should be targeted")
      {
        REQUIRE_FALSE(modif.doesTargetMonomer("M"));
        REQUIRE_FALSE(modif.doesTargetMonomer("C"));
        REQUIRE_FALSE(modif.doesTargetMonomer("A"));
      }
    }
  }
}

SCENARIO("A Modif can output itself as a string", "[Modif]")
{
  WHEN(
    "A Modif is created with PolChemDef, name, formula,  then set with targets "
    "and max count")
  {
    Modif modif(test_utils_1_letter_modif.msp_polChemDef,
                "Acetylation",
                "\"The title\"-H2O+CH3COOH");
    modif.setTargets("M;C");
    modif.setMaxCount(2);

    qDebug() << "The modif: " << modif.toString();

    THEN(
      "The Modif is valid and validates successfully with masses properly "
      "calculated")
    {
      REQUIRE(modif.isValid());

      error_list.clear();
      REQUIRE(modif.validate(&error_list));

      double mono = 0;
      double avg  = 0;

      modif.accountMasses(mono, avg, /*times*/ 1);

      REQUIRE_THAT(mono,
                   Catch::Matchers::WithinAbs(42.0105646847, 0.0000000001));
      REQUIRE_THAT(avg,
                   Catch::Matchers::WithinAbs(42.0369401545, 0.0000000001));
    }

    THEN("The string has the right contents")
    {
      REQUIRE(modif.toString().toStdString() ==
              "Acetylation, \"The title\"-H2O+CH3COOH, ;M;C;, 2");
    }
  }
}

SCENARIO("Modif instances can be constructed using a correct XML element",
         "[Modif]")
{
  QStringList dom_strings;
  dom_strings << "mdf"
              << "name"
              << "Acetylation"
              << "formula"
              << "-H2O+CH3COOH"
              << "targets"
              << "K"
              << "maxcount"
              << "3";


  GIVEN("A proper set of strings, a proper XML element can be crafted")
  {
    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(dom_strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    REQUIRE(
      document.toString().toStdString() ==
      "<mdf>\n <name>Acetylation</name>\n <formula>-H2O+CH3COOH</formula>\n "
      "<targets>K</targets>\n <maxcount>3</maxcount>\n</mdf>\n");

    // qDebug() << "The document:" << document.toString();

    WHEN("A Modif instance is allocated using that string and no PolChemDef")
    {
      Modif modif(nullptr, mdf_element, 1);

      THEN("The Modif instance has only partial proper member data")
      {
        REQUIRE(modif.getPolChemDefCstSPtr() == nullptr);
        REQUIRE(modif.getName().toStdString() == "Acetylation");
        REQUIRE(modif.getFormula().toStdString() == "-H2O+CH3COOH");
        REQUIRE(modif.getTargets().toStdString() == "K");
        REQUIRE(modif.getMaxCount() == -1);

        AND_THEN(
          "The Modif instance cannot validate successfully because of missing "
          "PolChemDef and targets string that could not validate because of "
          "the missing PolChemDef.")
        {
          error_list.clear();
          REQUIRE_FALSE(modif.validate(&error_list));
          REQUIRE_FALSE(modif.isValid());
        }
      }
    }

    WHEN("A Modif instance is allocated using that string and valid PolChemDef")
    {
      Modif modif =
        Modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance has proper member data")
      {
        REQUIRE(modif.getName().toStdString() == "Acetylation");
        REQUIRE(modif.getFormula().toStdString() == "-H2O+CH3COOH");
        REQUIRE(modif.getTargets().toStdString() == ";K;");
        REQUIRE(modif.getMaxCount() == 3);

        AND_THEN("The Modif instance is valid and must validate successfully")
        {
          REQUIRE(modif.isValid());

          error_list.clear();
          REQUIRE(modif.validate(&error_list));
        }
      }
    }
  }
}

SCENARIO(
  "Modif instances cannot be correctly constructed using incorrect XML "
  "elements",
  "[Modif]")
{
  QStringList dom_strings;
  dom_strings << "mdf"
              << "name"
              << "Acetylation"
              << "formula"
              << "-H2O+CH3COOH"
              << "targets"
              << "K"
              << "maxcount"
              << "3";

  // int mdf_element_index      = 0;
  // int name_element_index     = 1;
  // int name_text_index        = 2;
  // int formula_element_index  = 3;
  // int formula_text_index     = 4;
  // int targets_element_index  = 5;
  // int targets_text_index     = 6;
  // int maxcount_element_index = 7;
  // int maxcount_text_index    = 8;

  GIVEN("An XML element with an incorrect mdf element tag")
  {
    QStringList strings(dom_strings);
    strings[mdf_element_index] = "not_mdf";

    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    WHEN("A Modif instance is allocated using that string")
    {
      Modif modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance is incorrect")
      {
        REQUIRE(modif.getName().toStdString() == "");
        REQUIRE_FALSE(modif.isValid());
        REQUIRE_FALSE(modif.validate(&error_list));
      }
    }
  }

  GIVEN("An XML element with an incorrect name element tag")
  {
    QStringList strings(dom_strings);
    strings[name_element_index] = "not_name";

    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    WHEN("A Modif instance is allocated using that string")
    {
      Modif modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance is incorrect")
      {
        REQUIRE(modif.getName().toStdString() == "");
        REQUIRE_FALSE(modif.isValid());
        REQUIRE_FALSE(modif.validate(&error_list));
      }
    }
  }

  GIVEN("An XML element with an incorrect formula element tag")
  {
    QStringList strings(dom_strings);
    strings[formula_element_index] = "not_formula";

    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    WHEN("A Modif instance is allocated using that string")
    {
      Modif modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance is incorrect")
      {
        REQUIRE(modif.getName().toStdString() == "Acetylation");
        REQUIRE_FALSE(modif.isValid());
        REQUIRE_FALSE(modif.validate(&error_list));
      }
    }
  }

  GIVEN("An XML element with an incorrect formula element text")
  {
    QStringList strings(dom_strings);
    strings[formula_text_index] = "+h2O";

    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    WHEN("A Modif instance is allocated using that string")
    {
      Modif modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance is incorrect")
      {
        REQUIRE(modif.getName().toStdString() == "Acetylation");
        REQUIRE_FALSE(modif.isValid());
        REQUIRE_FALSE(modif.validate(&error_list));
      }
    }
  }

  GIVEN("An XML element with an incorrect target element tag")
  {
    QStringList strings(dom_strings);
    strings[targets_element_index] = "not-targets";

    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    WHEN("A Modif instance is allocated using that string")
    {
      Modif modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance is incorrect")
      {
        REQUIRE(modif.getName().toStdString() == "Acetylation");
        REQUIRE_FALSE(modif.isValid());
        REQUIRE_FALSE(modif.validate(&error_list));
      }
    }
  }

  GIVEN("An XML element with an incorrect target element text")
  {
    QStringList strings(dom_strings);
    strings[targets_text_index] = "$";

    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    WHEN("A Modif instance is allocated using that string")
    {
      Modif modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance is incorrect")
      {
        REQUIRE(modif.getName().toStdString() == "Acetylation");
        REQUIRE_FALSE(modif.isValid());
        REQUIRE_FALSE(modif.validate(&error_list));
      }
    }
  }

  GIVEN("An XML element with an incorrect target element text")
  {
    QStringList strings(dom_strings);
    strings[targets_text_index] = "m";

    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    WHEN("A Modif instance is allocated using that string")
    {
      Modif modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance is incorrect")
      {
        REQUIRE(modif.getName().toStdString() == "Acetylation");
        REQUIRE_FALSE(modif.isValid());
        REQUIRE_FALSE(modif.validate(&error_list));
      }
    }
  }

  GIVEN("An XML element with an incorrect max count element tag")
  {
    QStringList strings(dom_strings);
    strings[maxcount_element_index] = "not-maxcount";

    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    WHEN("A Modif instance is allocated using that string")
    {
      Modif modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance is incorrect")
      {
        REQUIRE(modif.getName().toStdString() == "Acetylation");
        REQUIRE_FALSE(modif.isValid());
        REQUIRE_FALSE(modif.validate(&error_list));
      }
    }
  }

  GIVEN("An XML element with an incorrect max count element text")
  {
    QStringList strings(dom_strings);
    strings[maxcount_text_index] = "-1";

    QDomDocument document =
      test_utils_1_letter_modif.craftMdfDomDocument(strings);
    QDomElement mdf_element =
      document.elementsByTagName(dom_strings[0]).item(0).toElement();

    WHEN("A Modif instance is allocated using that string")
    {
      Modif modif(test_utils_1_letter_modif.msp_polChemDef, mdf_element, 1);

      THEN("The Modif instance is incorrect")
      {
        REQUIRE(modif.getName().toStdString() == "Acetylation");
        REQUIRE_FALSE(modif.isValid());
        REQUIRE_FALSE(modif.validate(&error_list));
      }
    }
  }
}

SCENARIO("A Modif can output itself as an XML element string", "[Modif]")
{
  WHEN("A Modif is created with PolChemDef,  name and formula")
  {
    Modif modif(test_utils_1_letter_modif.msp_polChemDef,
                "Acetylation",
                "\"The title\"-H2O+CH3COOH");
    modif.setTargets("M;C");
    modif.setMaxCount(2);

    THEN(
      "The Modif is valid and validates successfully with masses properly "
      "calculated")
    {
      REQUIRE(modif.isValid());

      error_list.clear();
      REQUIRE(modif.validate(&error_list));

      double mono = 0;
      double avg  = 0;

      modif.accountMasses(mono, avg, /*times*/ 1);

      REQUIRE_THAT(mono,
                   Catch::Matchers::WithinAbs(42.0105646847, 0.0000000001));
      REQUIRE_THAT(avg,
                   Catch::Matchers::WithinAbs(42.0369401545, 0.0000000001));
    }

    THEN("The string has the right contents")
    {
      QString xml_element_string =
        modif.formatXmlMdfElement(0, Utils::xmlIndentationToken);
      QString expected_xml_string =
        "<mdf>\n"
        " <name>Acetylation</name>\n"
        " <formula>\"The title\"-H2O+CH3COOH</formula>\n"
        " <targets>;M;C;</targets>\n"
        " <maxcount>2</maxcount>\n"
        "</mdf>\n"
        "";

      REQUIRE(xml_element_string.toStdString() ==
              expected_xml_string.toStdString());
    }
  }
}


} // namespace libXpertMassCore
} // namespace MsXpS
