// Copyright (C) 2018  INRIA
//
// Treerecs is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Treerecs is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#include "gtest/gtest.h"

#include <string>

#include <TreerecsCliUtils.h>
#include <treerecs/Constants.h>
#include <treerecs/tools/utils.h>
#include <treerecs/tools/SpeciesGeneMapper.h>

#include "examples_paths.h"

using namespace treerecs;

class TreerecsCli_tests : public testing::Test {
protected:
  virtual void SetUp() {
    genetree_filename = multipolytomy_examples_path + "gene_tree.txt";
    speciestree_filename = multipolytomy_examples_path + "species_tree.txt";
    map_filename = multipolytomy_examples_path + "map.txt";
    alignment_filename = pll_fake_examples_path + "alignments.txt";

    char prog_name[] = "bin/treerecs";

    argv_no_option = {prog_name};

    argv_help = {prog_name, "-h"};

    argv_version = {prog_name, "-V"};

    argv_solving = {prog_name, "-g", genetree_filename,
                    "-s", speciestree_filename};

    argv_mapping_chars_expl = argv_solving;
    argv_mapping_chars_expl.reserve(argv_solving.capacity() + 4);
    argv_mapping_chars_expl.emplace_back("-c");
    argv_mapping_chars_expl.emplace_back("_");
    argv_mapping_chars_expl.emplace_back("-p");
    argv_mapping_chars_expl.emplace_back("yes");

    argv_mapping_file = argv_solving;
    argv_mapping_file.reserve(argv_solving.capacity() + 2);
    argv_mapping_file.emplace_back("-S");
    argv_mapping_file.emplace_back(map_filename);

    argv_rerooting = argv_solving;
    argv_rerooting.reserve(argv_solving.capacity() + 1);
    argv_rerooting.emplace_back("-r");

    argv_correction_one_threshold = argv_solving;
    argv_correction_one_threshold.reserve(argv_solving.capacity() + 2);
    argv_correction_one_threshold.emplace_back("-t");
    argv_correction_one_threshold.emplace_back("0.5");

    argv_correction_multi_threshold = argv_solving;
    argv_correction_multi_threshold.reserve(argv_solving.capacity() + 4);
    argv_correction_multi_threshold.emplace_back("-t");
    argv_correction_multi_threshold.emplace_back("0.5:0.6");
    argv_correction_multi_threshold.emplace_back("-t");
    argv_correction_multi_threshold.emplace_back("0.7:0.8:0.9:1.0");

    argv_correction_multi_format_outputs = argv_solving;
    argv_correction_multi_format_outputs.reserve(argv_solving.capacity() + 4);
    argv_correction_multi_format_outputs.emplace_back("-O");
    argv_correction_multi_format_outputs.emplace_back("nhx:NHX");
    argv_correction_multi_format_outputs.emplace_back("-O");
    argv_correction_multi_format_outputs.emplace_back("recphyloXML:svg");

    argv_likelihoods = argv_solving;
    argv_likelihoods.reserve(argv_solving.capacity() + 3);
    argv_likelihoods.emplace_back("-a");
    argv_likelihoods.emplace_back(alignment_filename);
    argv_likelihoods.emplace_back("--ale-evaluation");

    argv_other_options = argv_solving;
    argv_other_options.reserve(argv_solving.capacity() + 19);
    argv_other_options.emplace_back("-Y");
    argv_other_options.emplace_back("--info");
    argv_other_options.emplace_back("-d");
    argv_other_options.emplace_back("4");
    argv_other_options.emplace_back("-l");
    argv_other_options.emplace_back("12");
    argv_other_options.emplace_back("-C");
    argv_other_options.emplace_back("-n");
    argv_other_options.emplace_back("14");
    argv_other_options.emplace_back("-N");
    argv_other_options.emplace_back("140");
    argv_other_options.emplace_back("--number-of-threads");
    argv_other_options.emplace_back("2");
    argv_other_options.emplace_back("-M");
    argv_other_options.emplace_back("--stats");
    argv_other_options.emplace_back("--seed");
    argv_other_options.emplace_back("31082011");
    argv_other_options.emplace_back("--fevent");
    argv_other_options.emplace_back("--output-without-description");
  }

  virtual void TearDown() {}

  std::string genetree_filename;
  std::string speciestree_filename;
  std::string map_filename;
  std::string alignment_filename;

  std::vector<std::string> argv_no_option;

  std::vector<std::string> argv_help;

  std::vector<std::string> argv_version;

  std::vector<std::string> argv_solving;

  std::vector<std::string> argv_mapping_chars_expl;

  std::vector<std::string> argv_mapping_file;

  std::vector<std::string> argv_rerooting;

  std::vector<std::string> argv_correction_one_threshold;

  std::vector<std::string> argv_correction_multi_threshold;

  std::vector<std::string> argv_correction_multi_format_outputs;

  std::vector<std::string> argv_likelihoods;

  std::vector<std::string> argv_other_options;
};

TEST_F(TreerecsCli_tests, Parse_tests_no_option) {
  std::vector<char*> argv_no_option_c;
  argv_no_option_c.reserve(argv_no_option.size());

  for(std::size_t i = 0; i < argv_no_option.size(); ++i) {
    argv_no_option_c.push_back(const_cast<char*>(argv_no_option[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_THROW(
      params = ParseCommandLine(static_cast<int>(argv_no_option_c.size()),
                                argv_no_option_c.data()),
      malformed_cmd);
}

TEST_F(TreerecsCli_tests, Parse_tests_help) {
  std::vector<char*> argv_help_c;
  argv_help_c.reserve(argv_help.size());

  for(std::size_t i = 0; i < argv_help.size(); ++i) {
    argv_help_c.push_back(const_cast<char*>(argv_help[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(static_cast<int>(argv_help_c.size()),
                                argv_help_c.data()));

  ASSERT_STREQ("", params->genetrees_filename.c_str());
  ASSERT_STREQ("", params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::TREES == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_TRUE(params->thresholds_inputs.empty());
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::PRINT_HELP
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_version) {
  std::vector<char*> argv_version_c;
  argv_version_c.reserve(argv_version.size());

  for(std::size_t i = 0; i < argv_version.size(); ++i) {
    argv_version_c.push_back(const_cast<char*>(argv_version[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(static_cast<int>(argv_version_c.size()),
                                argv_version_c.data()));

  ASSERT_STREQ("", params->genetrees_filename.c_str());
  ASSERT_STREQ("", params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::TREES == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_TRUE(params->thresholds_inputs.empty());
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::PRINT_VERSION
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_solving) {
  std::vector<char*> argv_solving_c;
  argv_solving_c.reserve(argv_solving.size());

  for(std::size_t i = 0; i < argv_solving.size(); ++i) {
    argv_solving_c.push_back(const_cast<char*>(argv_solving[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(static_cast<int>(argv_solving_c.size()),
                                argv_solving_c.data()));

  ASSERT_STREQ(genetree_filename.c_str(), params->genetrees_filename.c_str());
  ASSERT_STREQ(speciestree_filename.c_str(),
               params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::TREES == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_TRUE(params->thresholds_inputs.empty());
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::RESOLVING
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_mapping_chars_expl) {
  std::vector<char*> argv_mapping_chars_expl_c;
  argv_mapping_chars_expl_c.reserve(argv_mapping_chars_expl.size());

  for (std::size_t i = 0; i < argv_mapping_chars_expl.size(); ++i) {
    argv_mapping_chars_expl_c.push_back(
        const_cast<char*>(argv_mapping_chars_expl[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(
          static_cast<int>(argv_mapping_chars_expl_c.size()),
          argv_mapping_chars_expl_c.data()));

  ASSERT_STREQ(genetree_filename.c_str(), params->genetrees_filename.c_str());
  ASSERT_STREQ(speciestree_filename.c_str(),
               params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::GENE_NAMES == params->mappingMethod);
  ASSERT_EQ("_",
            params->sep);
  ASSERT_EQ(true,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_TRUE(params->thresholds_inputs.empty());
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::RESOLVING
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_mapping_file) {
  std::vector<char*> argv_mapping_file_c;
  argv_mapping_file_c.reserve(argv_mapping_file.size());

  for (std::size_t i = 0; i < argv_mapping_file.size(); ++i) {
    argv_mapping_file_c.push_back(
        const_cast<char*>(argv_mapping_file[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(static_cast<int>(argv_mapping_file.size()),
                                argv_mapping_file_c.data()));

  ASSERT_STREQ(genetree_filename.c_str(), params->genetrees_filename.c_str());
  ASSERT_STREQ(speciestree_filename.c_str(),
               params->speciestree_filename.c_str());
  ASSERT_STREQ(map_filename.c_str(), params->map_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::SMAP == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_TRUE(params->thresholds_inputs.empty());
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::RESOLVING
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_rerooting) {
  std::vector<char*> argv_rerooting_c;
  argv_rerooting_c.reserve(argv_rerooting.size());

  for (std::size_t i = 0; i < argv_rerooting.size(); ++i) {
    argv_rerooting_c.push_back(
        const_cast<char*>(argv_rerooting[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(static_cast<int>(argv_rerooting.size()),
                                argv_rerooting_c.data()));

  ASSERT_STREQ(genetree_filename.c_str(), params->genetrees_filename.c_str());
  ASSERT_STREQ(speciestree_filename.c_str(),
               params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::TREES == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_TRUE(params->thresholds_inputs.empty());
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::REROOTING, Functionalities::RESOLVING
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_TRUE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_one_threshold) {
  std::vector<char*> argv_correction_one_threshold_c;
  argv_correction_one_threshold_c.reserve(argv_correction_one_threshold.size());

  for (std::size_t i = 0; i < argv_correction_one_threshold.size(); ++i) {
    argv_correction_one_threshold_c.push_back(
        const_cast<char*>(argv_correction_one_threshold[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(
          static_cast<int>(argv_correction_one_threshold.size()),
          argv_correction_one_threshold_c.data()));

  ASSERT_STREQ(genetree_filename.c_str(), params->genetrees_filename.c_str());
  ASSERT_STREQ(speciestree_filename.c_str(),
               params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::TREES == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_EQ(1, params->thresholds_inputs.size());
  ASSERT_STREQ("0.5", params->thresholds_inputs.front().c_str());
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::CORRECTION
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_multi_threshold) {
  std::vector<char*> argv_correction_multi_threshold_c;
  argv_correction_multi_threshold_c.reserve(
      argv_correction_multi_threshold.size());

  for (std::size_t i = 0; i < argv_correction_multi_threshold.size(); ++i) {
    argv_correction_multi_threshold_c.push_back(
        const_cast<char*>(argv_correction_multi_threshold[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(
          static_cast<int>(argv_correction_multi_threshold.size()),
          argv_correction_multi_threshold_c.data()));

  ASSERT_STREQ(genetree_filename.c_str(), params->genetrees_filename.c_str());
  ASSERT_STREQ(speciestree_filename.c_str(),
               params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::TREES == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_EQ(6, params->thresholds_inputs.size());
  std::vector<std::string> expected_thresholds_inputs = {
      "0.5", "0.6", "0.7", "0.8", "0.9", "1.0"
  };
  auto& observed_thresholds_inputs = params->thresholds_inputs;
  ASSERT_TRUE(utils::comp_all(expected_thresholds_inputs.begin(),
                              expected_thresholds_inputs.end(),
                              observed_thresholds_inputs.begin(),
                              observed_thresholds_inputs.end()));
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::CORRECTION
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_multi_outputs) {
  std::vector<char*> argv_correction_multi_outputs_c;
  argv_correction_multi_outputs_c.reserve(
      argv_correction_multi_format_outputs.size());

  for (std::size_t i = 0; i < argv_correction_multi_format_outputs.size(); ++i) {
    argv_correction_multi_outputs_c.push_back(
        const_cast<char*>(argv_correction_multi_format_outputs[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(
          static_cast<int>(argv_correction_multi_format_outputs.size()),
          argv_correction_multi_outputs_c.data()));

  ASSERT_STREQ(genetree_filename.c_str(), params->genetrees_filename.c_str());
  ASSERT_STREQ(speciestree_filename.c_str(),
               params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::TREES == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_TRUE(params->thresholds_inputs.empty());
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::RESOLVING
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(4, params->trees_output_formats.size());

  std::vector<TextFormat> expected_formats_inputs = {
      TextFormat::nhx, TextFormat::nhx,
      TextFormat::recphyloxml, TextFormat::svg
  };
  auto& observed_formats_inputs = params->trees_output_formats;
  ASSERT_TRUE(utils::comp_all(expected_formats_inputs.begin(),
                              expected_formats_inputs.end(),
                              observed_formats_inputs.begin(),
                              observed_formats_inputs.end()));

  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_likelihoods) {
  std::vector<char*> argv_likelihoods_c;
  argv_likelihoods_c.reserve(argv_likelihoods.size());

  for(std::size_t i = 0; i < argv_likelihoods.size(); ++i) {
    argv_likelihoods_c.push_back(const_cast<char*>(argv_likelihoods[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(static_cast<int>(argv_likelihoods_c.size()),
                                argv_likelihoods_c.data()));

  ASSERT_STREQ(genetree_filename.c_str(), params->genetrees_filename.c_str());
  ASSERT_STREQ(speciestree_filename.c_str(),
               params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());
  ASSERT_STREQ(alignment_filename.c_str(), params->alignments_filename.c_str());

  ASSERT_EQ(-1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::TREES == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(DEFAULT_DUPLICATION_COST, params->dupcost);
  ASSERT_EQ(DEFAULT_LOSS_COST, params->losscost);
  ASSERT_TRUE(params->thresholds_inputs.empty());
  ASSERT_EQ(DEFAULT_STRICT_SUPPORT_THRESHOLDS,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::PLL_LIKELIHOOD, Functionalities::ALE_LIKELIHOOD,
      Functionalities::RESOLVING
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(DEFAULT_SAMPLE_SIZE, params->sample_size);
  ASSERT_TRUE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_FALSE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_FALSE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_FALSE(params->saveMaps);
  ASSERT_FALSE(params->write_gene_relationships_summary);
  ASSERT_FALSE(params->statistics);

  ASSERT_EQ(Verbosity::NORMAL, params->verbosity);

  ASSERT_FALSE(params->seed_set);

  ASSERT_EQ(1, params->nthreads);
}

TEST_F(TreerecsCli_tests, Parse_tests_other_options) {
  std::vector<char*> argv_other_options_c;
  argv_other_options_c.reserve(argv_other_options.size());

  for(std::size_t i = 0; i < argv_other_options.size(); ++i) {
    argv_other_options_c.push_back(const_cast<char*>(argv_other_options[i].c_str()));
  }

  std::unique_ptr<TreerecsParameters> params;
  ASSERT_NO_THROW(
      params = ParseCommandLine(static_cast<int>(argv_other_options_c.size()),
                                argv_other_options_c.data()));

  ASSERT_STREQ(genetree_filename.c_str(), params->genetrees_filename.c_str());
  ASSERT_STREQ(speciestree_filename.c_str(),
               params->speciestree_filename.c_str());
  ASSERT_STREQ("", params->map_filename.c_str());
  ASSERT_STREQ("", params->alignments_filename.c_str());

  ASSERT_EQ(140 - 1, params->genetree_index);
  ASSERT_TRUE(MappingMethod::TREES == params->mappingMethod);
  ASSERT_EQ(DEFAULT_SEPARATION_CHARACTER_BETWEEN_GENE_AND_SPECIES_NAME,
            params->sep);
  ASSERT_EQ(DEFAULT_SPECIES_NAME_IS_PREFIX_IN_GENE_NAME,
            params->prefix);

  ASSERT_EQ(4, params->dupcost);
  ASSERT_EQ(12, params->losscost);
  ASSERT_TRUE(params->thresholds_inputs.empty());
  ASSERT_EQ(true,
            params->strict_support_thresholds);

  std::set<Functionalities> expected_functionalities {
      Functionalities::PRINT_SUPPORT_DIAGRAM, Functionalities::COST_ESTIMATION,
      Functionalities::RESOLVING
  };

  ASSERT_EQ(expected_functionalities, params->functionalities);
  ASSERT_FALSE(params->reroot);
  ASSERT_EQ(14, params->sample_size);
  ASSERT_FALSE(params->add_ale_evaluation);
  ASSERT_FALSE(params->ale_selection);
  ASSERT_TRUE(params->costs_estimation);

  ASSERT_STREQ("", params->output.c_str());
  ASSERT_TRUE(params->output_without_description);
  ASSERT_EQ(0, params->trees_output_formats.size());
  ASSERT_TRUE(params->saveMaps);
  ASSERT_TRUE(params->write_gene_relationships_summary);
  ASSERT_TRUE(params->statistics);

  ASSERT_EQ(Verbosity::CHATTY, params->verbosity);

  ASSERT_TRUE(params->seed_set);
  ASSERT_EQ(31082011, params->seed);

  ASSERT_EQ(2, params->nthreads);
}
