//    TapTempo, a command line tap tempo.
//    Copyright (C) 2017 Francois Mazen
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program 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 General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <https://www.gnu.org/licenses/>.

#include "../src/options.h"

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

#define DEFAULT_SAMPLE_SIZE 5
#define DEFAULT_RESET_TIME 5
#define DEFAULT_PRECISION 0
#define MAX_PRECISION 5

TEST_CASE("Invalid args should returns default options")
{
    Options options = Options::createFromArgs(0, 0);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Zero args should returns default options")
{
    char programName[] = "taptempo";
    char* argPointer = &programName[0];
    Options options = Options::createFromArgs(1, &argPointer);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Help switch should exit")
{
    char programName[] = "taptempo";
    char helpSwitch[] = "--help";
    char* arguments[2] = {programName, helpSwitch};
    Options options = Options::createFromArgs(2, arguments);
    REQUIRE(options.getShouldExit() == true);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Short help switch should exit")
{
    char programName[] = "taptempo";
    char helpSwitch[] = "-h";
    char* arguments[2] = {programName, helpSwitch};
    Options options = Options::createFromArgs(2, arguments);
    REQUIRE(options.getShouldExit() == true);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Version switch should exit")
{
    char programName[] = "taptempo";
    char versionSwitch[] = "--version";
    char* arguments[2] = {programName, versionSwitch};
    Options options = Options::createFromArgs(2, arguments);
    REQUIRE(options.getShouldExit() == true);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Short version switch should exit")
{
    char programName[] = "taptempo";
    char versionSwitch[] = "-v";
    char* arguments[2] = {programName, versionSwitch};
    Options options = Options::createFromArgs(2, arguments);
    REQUIRE(options.getShouldExit() == true);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Precision switch should return the right value")
{
    char programName[] = "taptempo";
    char precisionSwitch[] = "--precision";
    char precisionValue[] = "2";
    char* arguments[3] = {programName, precisionSwitch, precisionValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == 2);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Short precision switch should return the right value")
{
    char programName[] = "taptempo";
    char precisionSwitch[] = "-p";
    char precisionValue[] = "2";
    char* arguments[3] = {programName, precisionSwitch, precisionValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == 2);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Wrong precision switch should return the default value")
{
    char programName[] = "taptempo";
    char precisionSwitch[] = "--precision";
    char precisionValue[] = "0";
    char* arguments[3] = {programName, precisionSwitch, precisionValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Out of bound precision switch should return the max value")
{
    char programName[] = "taptempo";
    char precisionSwitch[] = "--precision";
    char precisionValue[] = "10";
    char* arguments[3] = {programName, precisionSwitch, precisionValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == MAX_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Sample size switch should return the right value")
{
    char programName[] = "taptempo";
    char sampleSizeSwitch[] = "--sample-size";
    char sampleSizeValue[] = "10";
    char* arguments[3] = {programName, sampleSizeSwitch, sampleSizeValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == 10);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Short sample size switch should return the right value")
{
    char programName[] = "taptempo";
    char sampleSizeSwitch[] = "-s";
    char sampleSizeValue[] = "10";
    char* arguments[3] = {programName, sampleSizeSwitch, sampleSizeValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == 10);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Wrong sample size switch should return the default value")
{
    char programName[] = "taptempo";
    char sampleSizeSwitch[] = "--sample-size";
    char sampleSizeValue[] = "0";
    char* arguments[3] = {programName, sampleSizeSwitch, sampleSizeValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Reset time switch should return the right value")
{
    char programName[] = "taptempo";
    char resetTimeSwitch[] = "--reset-time";
    char resetTimeValue[] = "10";
    char* arguments[3] = {programName, resetTimeSwitch, resetTimeValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == 10);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Short reset time switch should return the right value")
{
    char programName[] = "taptempo";
    char resetTimeSwitch[] = "-r";
    char resetTimeValue[] = "10";
    char* arguments[3] = {programName, resetTimeSwitch, resetTimeValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == 10);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("Wrong reset time switch should return the default value")
{
    char programName[] = "taptempo";
    char resetTimeSwitch[] = "-r";
    char resetTimeValue[] = "-10";
    char* arguments[3] = {programName, resetTimeSwitch, resetTimeValue};
    Options options = Options::createFromArgs(3, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == false);
}

TEST_CASE("All switchs should return the right values")
{
    char programName[] = "taptempo";
    char sampleSizeSwitch[] = "-s";
    char sampleSizeValue[] = "6";
    char resetTimeSwitch[] = "--reset-time";
    char resetTimeValue[] = "10";
    char precisionSwitch[] = "--precision";
    char precisionValue[] = "2";
    char gameSwitch[] = "--game";
    char* arguments[8] = {programName,
                          sampleSizeSwitch,
                          sampleSizeValue,
                          resetTimeSwitch,
                          resetTimeValue,
                          precisionSwitch,
                          precisionValue,
                          gameSwitch};
    Options options = Options::createFromArgs(8, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == 2);
    REQUIRE(options.getSampleSize() == 6);
    REQUIRE(options.getResetTime() == 10);
    REQUIRE(options.getIsGamingMode() == true);
}

TEST_CASE("Game switch should return the right value")
{
    char programName[] = "taptempo";
    char gameSwitch[] = "--game";
    char* arguments[3] = {programName, gameSwitch};
    Options options = Options::createFromArgs(2, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == true);
}

TEST_CASE("Short game switch should return the right value")
{
    char programName[] = "taptempo";
    char gameSwitch[] = "-g";
    char* arguments[3] = {programName, gameSwitch};
    Options options = Options::createFromArgs(2, arguments);
    REQUIRE(options.getShouldExit() == false);
    REQUIRE(options.getPrecision() == DEFAULT_PRECISION);
    REQUIRE(options.getSampleSize() == DEFAULT_SAMPLE_SIZE);
    REQUIRE(options.getResetTime() == DEFAULT_RESET_TIME);
    REQUIRE(options.getIsGamingMode() == true);
}
