header:
#pragma once

#include <cstdlib>
#include <string>
#include <vector>

namespace ArgumentParser {

class ArgParser {
public:
  ArgParser(const std::string& name) : name(name) {}

  ~ArgParser();
  
  bool Parse(const std::vector<std::string>& argv);

  ArgParser& AddStringArgument(std::string long_name);

  ArgParser& AddStringArgument(char short_name);

  ArgParser& AddStringArgument(char short_name, std::string argument); 

  std::string GetStringValue(std::string long_name);

  std::string GetStringValue(char short_name);

  ArgParser& StoreValue(std::string& value);

  ArgParser& Default(const char* default_value);

  ArgParser& AddIntArgument(std::string argument);

  ArgParser& AddIntArgument(char short_name, std::string argument);

  ArgParser& AddIntArgument(char short_name);

  int32_t GetIntValue(std::string long_name);

  int32_t GetIntValue(char short_name);

  int32_t GetIntValue(std::string long_name, int32_t index);

  int32_t GetIntValue(char short_name, int32_t index);

  ArgParser& StoreValues(std::vector<int32_t>& values);

  ArgParser& MultiValue();

  ArgParser& MultiValue(size_t min_arguments_count);

  ArgParser& AddFlag(char short_name, std::string long_name);

  ArgParser& AddFlag(char short_name);

  ArgParser& AddFlag(std::string long_name);

  bool GetFlag(char short_name);

  bool GetFlag(std::string long_name);

  ArgParser& Default(bool value);

  ArgParser& StoreValue(bool& value);

  ArgParser& Positional();

  ArgParser& AddHelp(char short_name, std::string long_name, std::string description);

  bool Help();

  std::string HelpDescription();

  ArgParser& AddStringArgumentWithDescription(std::string long_name, std::string description);

  ArgParser& AddStringArgumentWithDescription(char short_name, std::string description);

  ArgParser& AddStringArgumentWithDescription(char short_name, std::string long_name, std::string description);

  ArgParser& AddIntArgumentWithDescription(std::string long_name, std::string description);

  ArgParser& AddIntArgumentWithDescription(char short_name, std::string description);

  ArgParser& AddIntArgumentWithDescription(char short_name, std::string long_name, std::string description);

  ArgParser& AddFlagWithDescription(std::string long_name, std::string description);

  ArgParser& AddFlagWithDescription(char short_name, std::string description);

  ArgParser& AddFlagWithDescription(char short_name, std::string long_name, std::string description);

private:
  std::string name;

  class Argument {
  public:
    enum class Type { String, Integer, Bool };

    std::string long_name;
    char short_name;
    Type type;
    size_t min_arguments_count = 1;
    bool is_multi_value = false;
    bool is_positional = false;
    bool help_requested = false;
    std::string help_message;
    bool is_default = false;

    Argument(Type t) : type(t) {}
  };

  class StringArgument : public Argument {
  public:
    std::vector<std::string> value;
    std::string* str_value_ptr = nullptr;

    StringArgument()
      : Argument(Type::String) {}
  };

  class IntArgument : public Argument {
  public:
    std::vector<int32_t> value;
    std::vector<int32_t>* int_values_ptr = nullptr;

    IntArgument() : Argument(Type::Integer) {}
  };

  class BoolArgument : public Argument {
  public:
    bool value = false;
    bool* bool_value_ptr = nullptr;

    BoolArgument() : Argument(Type::Bool) {}
  };

  std::vector<Argument*> arguments;

  int32_t FindByLongName(const std::string& long_name);

  int32_t FindByShortName(char short_name);

};

}  // namespace ArgumentParser


cpp file:
#include "ArgParser.h"
#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <string_view>

namespace ArgumentParser {

ArgParser::~ArgParser() {
  for (Argument* arg : arguments) {
    delete arg;
  }
}

bool IsValue(const std::string& buff) {
  return buff.size() == 1 || std::isdigit(buff[1]);
}

int32_t ArgParser::FindByLongName(const std::string& long_name) {
  for (int i = 0; i < arguments.size(); ++i) {
    if (arguments[i]->long_name == long_name) {
      return i;
    }
  }
  return -1;
}

int32_t ArgParser::FindByShortName(char short_name) {
  for (int i = 0; i < arguments.size(); ++i) {
    if (arguments[i]->short_name == short_name) {
      return i;
    }
  }
  return -1;
}



bool ArgParser::Parse(std::vector<std::string> argv) {
  if (arguments.empty()) {
    return true;
  }

  for (int i = 1; i < argv.size(); ++i) {

    if (argv[i][0] != '-' || arguments[FindByLongName(argv[i].substr(1))].is_positional || 
      arguments[FindByShortName(argv[i][1])].is_positional) {
      int positional_index = -1;
      for (int j = 0; j < arguments.size(); ++j) {
        if (arguments[j].is_positional) {
          positional_index = j;
          break;
        }
      }

      if (positional_index != -1) {
        arguments[positional_index].value.push_back(argv[i]);
        if (arguments[positional_index].is_store_value) {
          if (arguments[positional_index].argument_type == "int")
            arguments[positional_index].int_values_ptr->push_back(stoi(argv[i]));
          else if (arguments[positional_index].argument_type == "string")
            *arguments[positional_index].str_values_ptr = argv[i];
          else if(arguments[positional_index].argument_type == "bool")
            *arguments[positional_index].bool_values_ptr = argv[i]=="true"; 
        }
      } 
    } else {
      if (argv[i][1] != '-' && argv[i].find("=") == std::string::npos) { 
        for (size_t j = 1; j < argv[i].size(); ++j) { 
          std::string arg(1, argv[i][j]);
          int index_of_argument = FindByShortName(arg[0]);
          if (arguments[index_of_argument].argument_type == "bool") {
            arguments[index_of_argument].value.push_back("1");
            if (arguments[index_of_argument].is_store_value) {
              *arguments[index_of_argument].bool_values_ptr = true;
            }
          }
        }
      } else {
        std::string arg;
        std::string value;
        size_t equal_pos = argv[i].find("=");
        if(equal_pos != std::string::npos) {
          if(argv[i][1] == '-'){
            arg = argv[i].substr(2, equal_pos - 2);
          } else{
            arg = argv[i].substr(1, equal_pos - 1);
          }
          value = argv[i].substr(equal_pos + 1);
        } else {
          arg = argv[i].substr(2);
        }

        int index_of_argument = FindByLongName(arg);
        if (index_of_argument == -1) {
          index_of_argument = FindByShortName(arg[0]);
        }

        if (arguments[index_of_argument].argument_type == "int") {
          if (arguments[index_of_argument].is_multi_value) {
            arguments[index_of_argument].value.push_back(value);
            if (arguments[index_of_argument].is_store_value) {
              arguments[index_of_argument].int_values_ptr->push_back(stoi(value));
            }
          } else {
            arguments[index_of_argument].value.clear();
            arguments[index_of_argument].value.push_back(value);
            if (arguments[index_of_argument].is_store_value) {
              arguments[index_of_argument].int_values_ptr->clear();
              arguments[index_of_argument].int_values_ptr->push_back(stoi(value));
            }
          }
        } else if (arguments[index_of_argument].argument_type == "string") {
          arguments[index_of_argument].value.push_back(value);
          if (arguments[index_of_argument].is_store_value) {
              *arguments[index_of_argument].str_values_ptr = value;
          } 
          if (arguments[index_of_argument].value.size() > 0 && arguments[index_of_argument].is_multi_value) {
              arguments[index_of_argument].value.push_back(value);
          }
        } else if (arguments[index_of_argument].argument_type == "bool") {
          arguments[index_of_argument].value.push_back("1");
          if(arguments[index_of_argument].is_store_value) {
            *arguments[index_of_argument].bool_values_ptr = true;
          }
        
      }
      }
    }
  }

  for(const auto& argument : arguments) {
    if((argument.value.empty() || argument.value.size() < argument.min_arguments_count) && !argument.help_requested) {
      return false;
    }
  }

  return true;
}

ArgParser& ArgParser::AddStringArgument(std::string long_name) {
    StringArgument* arg = new StringArgument();
    arg->long_name = std::move(long_name);
    arguments.push_back(arg);
    return *this;
}

ArgParser& ArgParser::AddStringArgument(char short_name) {
  StringArgument* arg = new StringArgument();
  arg->short_name = short_name;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddStringArgument(char short_name, std::string long_name) {
  StringArgument* arg = new StringArgument();
  arg->long_name = std::move(long_name);
  arg->short_name = short_name;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::StoreValue(std::string& value) {
    if (arguments.back()->type == Argument::Type::String) {
        StringArgument* stringArg = static_cast<StringArgument*>(arguments.back());
        stringArg->str_value_ptr = &value;
        stringArg->is_default = true;
    }
    return *this;
}

std::string ArgParser::GetStringValue(std::string long_name) {
    int32_t index = FindByLongName(long_name);
    if (index != -1 && arguments[index]->type == Argument::Type::String) {
        StringArgument* stringArg = static_cast<StringArgument*>(arguments[index]);
        if (!stringArg->value.empty()) return stringArg->value.front();
    }
    return "";
}

std::string ArgParser::GetStringValue(char short_name) {
    int32_t index = FindByShortName(short_name);
    if (index != -1 && arguments[index]->type == Argument::Type::String) {
        StringArgument* stringArg = static_cast<StringArgument*>(arguments[index]);
        if (!stringArg->value.empty()) return stringArg->value.front();
    }
    return "";
}

ArgParser& ArgParser::Default(const char* default_value) {
    if (arguments.back()->type == Argument::Type::String) {
        StringArgument* stringArg = static_cast<StringArgument*>(arguments.back());
        if (stringArg->value.empty()) {
            stringArg->value.push_back(default_value);
        }
        stringArg->is_default = true;
    } else {
        // Handle error or add type checking
    }
    return *this;
}
ArgParser& ArgParser::AddIntArgument(std::string long_name) {
  IntArgument* arg = new IntArgument();
  arg->long_name = std::move(long_name);
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddIntArgument(char short_name) {
  IntArgument* arg = new IntArgument();
  arg->short_name = short_name;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddIntArgument(char short_name, std::string long_name) {
  IntArgument* arg = new IntArgument();
  arg->long_name = std::move(long_name);
  arg->short_name = short_name;
  arguments.push_back(arg);
  return *this;
}

int32_t ArgParser::GetIntValue(std::string long_name) {
    int32_t index = FindByLongName(long_name);
    if (index != -1 && arguments[index]->type == Argument::Type::Integer) {
        IntArgument* intArg = static_cast<IntArgument*>(arguments[index]);
        if (!intArg->value.empty()) return intArg->value.front();
    }
    return 0; // Return error or throw exception
}

int32_t ArgParser::GetIntValue(char short_name) {
    int32_t index = FindByShortName(short_name);
    if (index != -1 && arguments[index]->type == Argument::Type::Integer) {
        IntArgument* intArg = static_cast<IntArgument*>(arguments[index]);
        if (!intArg->value.empty()) return intArg->value.front();
    }
    return 0; // Return error or throw exception
}

int32_t ArgParser::GetIntValue(std::string long_name, int32_t index) {
    int32_t index_of_argument = FindByLongName(long_name);
    IntArgument* intArg = static_cast<IntArgument*>(arguments[index_of_argument]);
    return intArg->value[index];
}

ArgParser& ArgParser::StoreValues(std::vector<int32_t>& values) {
    if (arguments.back()->type == Argument::Type::Integer) {
        IntArgument* intArg = static_cast<IntArgument*>(arguments.back());
        intArg->int_values_ptr = &values;
        intArg->is_default = true;
    }
    return *this;
}

ArgParser& ArgParser::MultiValue() {
  arguments.back()->is_multi_value = true;
  return *this;
}

ArgParser& ArgParser::MultiValue(size_t min_arguments_count) {
  arguments.back()->is_multi_value = true;
  arguments.back()->min_arguments_count = min_arguments_count;

  return *this;
}

ArgParser& ArgParser::AddFlag(char short_name, std::string long_name) {
  BoolArgument* arg = new BoolArgument;
  arg->long_name = std::move(long_name);
  arg->short_name = short_name;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddFlag(char short_name) {
  BoolArgument* arg = new BoolArgument;
  arg->short_name = short_name;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddFlag(std::string long_name) {
  BoolArgument* arg = new BoolArgument;
  arg->long_name = std::move(long_name);
  arguments.push_back(arg);
  return *this;
}

bool ArgParser::GetFlag(char short_name) {
    int32_t index = FindByShortName(short_name);
    if (index != -1 && arguments[index]->type == Argument::Type::Bool) {
        BoolArgument* boolArg = static_cast<BoolArgument*>(arguments[index]);
        return boolArg->value;
    }
    return false; // Return error or throw exception
}

bool ArgParser::GetFlag(std::string long_name) {
    int32_t index = FindByLongName(long_name);
    if (index != -1 && arguments[index]->type == Argument::Type::Bool) {
        BoolArgument* boolArg = static_cast<BoolArgument*>(arguments[index]);
        return boolArg->value;
    }
    return false; // Return error or throw exception
}

ArgParser& ArgParser::Default(bool value) {
    if (arguments.back()->type == Argument::Type::Bool) {
        BoolArgument* boolArg = static_cast<BoolArgument*>(arguments.back());
        boolArg->value = value;
        boolArg->is_default = true;
    } else {
        // Handle error or add type checking
    }
    return *this;
}

ArgParser& ArgParser::StoreValue(bool& value) {
    if (arguments.back()->type == Argument::Type::Bool) {
        BoolArgument* boolArg = static_cast<BoolArgument*>(arguments.back());
        boolArg->bool_value_ptr = &value;
        boolArg->is_default = true;
    }
    return *this;
}

ArgParser& ArgParser::Positional() {
  arguments.back()->is_positional = true;
  return *this;
}

ArgParser& ArgParser::AddHelp(char short_name, std::string long_name, std::string description) {
  BoolArgument* arg = new BoolArgument();
  arg->short_name = short_name;
  arg->long_name = std::move(long_name);
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}

bool ArgParser::Help() {
  for(int i = 0; i < arguments.size(); ++i) {
    if (arguments[i]->help_requested) {
      return true;
    }
  }
  return false;
}

std::string ArgParser::HelpDescription() {
    std::stringstream help_string;
    help_string << name << "\n";
    
    for (const auto &arg : arguments) {
        if (arg->help_requested) {
            help_string << arg->help_message << "\n\n";
            continue;
        }
        help_string << (arg->short_name != '\0' ? "-" : "") 
                    << (arg->short_name != '\0' ? std::string(1, arg->short_name) + ", " : "")
                    << (!arg->long_name.empty() ? "-" : "")
                    << arg->long_name;
        switch (arg->type) {
            case Argument::Type::String: help_string << ", <string>"; break;
            case Argument::Type::Integer: help_string << ", <integer>"; break;
            case Argument::Type::Bool: help_string << ", <bool>"; break;
        }
        help_string << ", " << arg->help_message;


    if (arg->is_multi_value) {
      help_string << " [repeated";
      if (arg->min_arguments_count > 0) {
        help_string << ", min args = " << arg->min_arguments_count;
      }
      help_string << "]";
    }
    
    if (arg->is_default) {
      if(arg->type == Argument::Type::String){
        if (arg->is_default) {
          help_string << " [default = " << static_cast<StringArgument*>(arg)->value[0] << "]";
        }
      }else if(arg->type == Argument::Type::Integer && arg->is_default && !static_cast<IntArgument*>(arg)->value.empty()){
        help_string << " [default = " << static_cast<IntArgument*>(arg)->value[0] << "]";
      }else if(arg->type == Argument::Type::Bool){
        if (arg->is_default) {
          help_string << " [default = " << (static_cast<BoolArgument*>(arg)->value ? "true" : "false") << "]";
        }
      }
    }
    help_string << "\n\n";
  }
  help_string << "\n\n" << (arguments[0]->short_name != 0 ? "-" : "") 
            << (arguments[0]->short_name != 0 ? std::string(1, arguments[0]->short_name) + ", " : "")
            << "--help Display this help and exit\n";

  return help_string.str();
}



ArgParser& ArgParser::AddStringArgumentWithDescription(std::string long_name, std::string description) {
  StringArgument* arg = new StringArgument();
  arg->long_name = std::move(long_name);
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddStringArgumentWithDescription(char short_name, std::string description) {
  StringArgument* arg = new StringArgument();
  arg->short_name = short_name;
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddStringArgumentWithDescription(char short_name, std::string long_name, std::string description) {
  StringArgument* arg = new StringArgument();
  arg->long_name = std::move(long_name);
  arg->short_name = short_name;
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddIntArgumentWithDescription(std::string long_name, std::string description) {
  IntArgument* arg = new IntArgument();
  arg->long_name = std::move(long_name);
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddIntArgumentWithDescription(char short_name, std::string description) {
  IntArgument* arg = new IntArgument();
  arg->short_name = short_name;
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddIntArgumentWithDescription(char short_name, std::string long_name, std::string description) {
  IntArgument* arg = new IntArgument();
  arg->long_name = std::move(long_name);
  arg->short_name = short_name;
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddFlagWithDescription(std::string long_name, std::string description) {
  BoolArgument* arg = new BoolArgument();
  arg->long_name = std::move(long_name);
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddFlagWithDescription(char short_name, std::string description) {
  BoolArgument* arg = new BoolArgument();
  arg->short_name = short_name;
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}

ArgParser& ArgParser::AddFlagWithDescription(char short_name, std::string long_name, std::string description) {
  BoolArgument* arg = new BoolArgument();
  arg->long_name = std::move(long_name);
  arg->short_name = short_name;
  arg->help_message = std::move(description);
  arg->help_requested = true;
  arguments.push_back(arg);
  return *this;
}
} // namespace ArgumentParser



tests case:
#include <gtest/gtest.h>
#include <lib/ArgParser.h>

#include <sstream>
#include <vector>

using namespace ArgumentParser;

/*
    Функция принимает в качество аргумента строку, разделяет ее по "пробелу"
    и возвращает вектор полученных слов
*/
std::vector<std::string> SplitString(const std::string& str) {
  std::istringstream iss(str);

  return {std::istream_iterator<std::string>(iss),
          std::istream_iterator<std::string>()};
}

TEST(ArgParserTestSuite, EmptyTest) {
  ArgParser parser("My Empty Parser");

  ASSERT_TRUE(parser.Parse(SplitString("app")));
}

TEST(ArgParserTestSuite, StringTest) {
  ArgParser parser("My Parser");
  parser.AddStringArgument("param1");

  ASSERT_TRUE(parser.Parse(SplitString("app --param1=value1")));
  ASSERT_EQ(parser.GetStringValue("param1"), "value1");
}

TEST(ArgParserTestSuite, ShortNameTest) {
  ArgParser parser("My Parser");
  parser.AddStringArgument('p', "param1");

  ASSERT_TRUE(parser.Parse(SplitString("app -p=value1")));
  ASSERT_EQ(parser.GetStringValue("param1"), "value1");
}

TEST(ArgParserTestSuite, DefaultTest) {
  ArgParser parser("My Parser");
  parser.AddStringArgument("param1").Default("value1");

  ASSERT_TRUE(parser.Parse(SplitString("app")));
  ASSERT_EQ(parser.GetStringValue("param1"), "value1");
}

TEST(ArgParserTestSuite, NoDefaultTest) {
  ArgParser parser("My Parser");
  parser.AddStringArgument("param1");

  ASSERT_FALSE(parser.Parse(SplitString("app")));
}

TEST(ArgParserTestSuite, StoreValueTest) {
  ArgParser parser("My Parser");
  std::string value;
  parser.AddStringArgument("param1").StoreValue(value);

  ASSERT_TRUE(parser.Parse(SplitString("app --param1=value1")));
  ASSERT_EQ(value, "value1");
}

TEST(ArgParserTestSuite, MultiStringTest) {
  ArgParser parser("My Parser");
  std::string value;
  parser.AddStringArgument("param1").StoreValue(value);
  parser.AddStringArgument('a', "param2");

  ASSERT_TRUE(parser.Parse(SplitString("app --param1=value1 --param2=value2")));
  ASSERT_EQ(parser.GetStringValue("param2"), "value2");
}

TEST(ArgParserTestSuite, IntTest) {
  ArgParser parser("My Parser");
  parser.AddIntArgument("param1");

  ASSERT_TRUE(parser.Parse(SplitString("app --param1=100500")));
  ASSERT_EQ(parser.GetIntValue("param1"), 100500);
}

TEST(ArgParserTestSuite, MultiValueTest) {
  ArgParser parser("My Parser");
  std::vector<int> int_values;
  parser.AddIntArgument('p', "param1").MultiValue().StoreValues(int_values);

  ASSERT_TRUE(
      parser.Parse(SplitString("app --param1=1 --param1=2 --param1=3")));
  ASSERT_EQ(parser.GetIntValue("param1", 0), 1);
  ASSERT_EQ(int_values[1], 2);
  ASSERT_EQ(int_values[2], 3);
}

TEST(ArgParserTestSuite, MinCountMultiValueTest) {
  ArgParser parser("My Parser");
  std::vector<int> int_values;
  size_t MinArgsCount = 10;
  parser.AddIntArgument('p', "param1")
      .MultiValue(MinArgsCount)
      .StoreValues(int_values);

  ASSERT_FALSE(
      parser.Parse(SplitString("app --param1=1 --param1=2 --param1=3")));
}

TEST(ArgParserTestSuite, FlagTest) {
  ArgParser parser("My Parser");
  parser.AddFlag('f', "flag1");

  ASSERT_TRUE(parser.Parse(SplitString("app --flag1")));
  ASSERT_TRUE(parser.GetFlag("flag1"));
}

TEST(ArgParserTestSuite, FlagsTest) {
  ArgParser parser("My Parser");
  bool flag3;
  parser.AddFlag('a', "flag1");
  parser.AddFlag('b', "flag2").Default(true);
  parser.AddFlag('c', "flag3").StoreValue(flag3);

  ASSERT_TRUE(parser.Parse(SplitString("app -ac")));
  ASSERT_TRUE(parser.GetFlag("flag1"));
  ASSERT_TRUE(parser.GetFlag("flag2"));
  ASSERT_TRUE(flag3);
}

TEST(ArgParserTestSuite, PositionalArgTest) {
  ArgParser parser("My Parser");
  std::vector<int> values;
  parser.AddIntArgument("Param1").MultiValue(1).Positional().StoreValues(
      values);

  ASSERT_TRUE(parser.Parse(SplitString("app 1 2 3 4 5")));
  ASSERT_EQ(values[0], 1);
  ASSERT_EQ(values[2], 3);
  ASSERT_EQ(values.size(), 5);
}

TEST(ArgParserTestSuite, HelpTest) {
  ArgParser parser("My Parser");
  parser.AddHelp('h', "help", "Some Description about program");

  ASSERT_TRUE(parser.Parse(SplitString("app --help")));
  ASSERT_TRUE(parser.Help());
}

TEST(ArgParserTestSuite, HelpStringTest) {
  ArgParser parser("My Parser");
  parser.AddHelp('h', "help", "Some Description about program");
  parser.AddStringArgumentWithDescription('i', "input", "File path for input file")
      .MultiValue(1);
  parser.AddFlagWithDescription('s', "flag1", "Use some logic").Default(true);
  parser.AddFlagWithDescription('p', "flag2", "Use some logic");
  parser.AddIntArgumentWithDescription("number", "Some Number");

  ASSERT_TRUE(parser.Parse(SplitString("app --help")));
  // Проверка закоментирована намеренно. Ождиается, что результат вызова функции
  // будет приблизительно такой же, но не с точностью до символа

//   ASSERT_EQ(
//   parser.HelpDescription(),
//   "My Parser\n"
// "Some Description about program\n\n"
// "-i, --input=<string>, File path for input file [repeated, min args = 1]"
// "-s, --flag1=<bool>, Use some logic [default = true]"
// "-p, --flag2=<bool>, Use some logic"
// "--number=<int>, Some Number"
// "-h, --help Display this help and exit"

//);

}




rework Parse for new implementation