//
// Unit tests
//
// Copyright 2026, Jakob Østergaard Hegelund <joe@unthought.net>
// -----------------------------------------------------------------------
// This file is part of FanMan.
//
// FanMan 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.
//
// FanMan 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 FanMan. If not, see <https://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------
//

#include "cfgparser.hh"
#include <stdexcept>
#include <iostream>

#define require(...) \
{ bool res = (__VA_ARGS__); \
  if (!res) { \
    throw std::runtime_error(#__VA_ARGS__); \
  } \
}

#define reqthrow(...) \
{ try { \
    __VA_ARGS__; \
    throw std::runtime_error(#__VA_ARGS__); \
  } catch (const std::exception &) { \
  } \
}

void test_cfgparameter();
void test_cfgparser();


int main() try
{
  test_cfgparameter();
  test_cfgparser();

} catch(const std::exception &e) {
  std::cerr << "Error: " << e.what() << std::endl;
  return 1;
}

void test_cfgparameter()
{
  // Integer tests
  CfgParameter<size_t> p_foo("foo", 17);
  require(p_foo == 17);

  // Test basic comment/blank parsing
  std::string str_comment = "# comment";
  require(p_foo.parse(str_comment));
  std::string str_blank = "";
  require(p_foo.parse(str_blank));

  // Test first integer parse
  std::string str_ourname = "foo = 42";
  require(p_foo.parse(str_ourname));
  require(p_foo == 42);

  // Test integer reparse
  std::string str_ourname_v2 = "foo = 86";
  require(p_foo.parse(str_ourname_v2));
  require(p_foo == 86);

  // Test we don't parse others
  require(!p_foo.parse("bar = 42"));

  // Test integer reparse with different spacing on assignment
  require(p_foo.parse("foo=1"));
  require(p_foo.parse("foo =1"));
  require(p_foo.parse("foo= 1"));
  require(p_foo.parse("foo = 1"));

  // Test malformed lines
  reqthrow(p_foo.parse(" # bad comment"));
  reqthrow(p_foo.parse(" "));
  reqthrow(p_foo.parse(" foo = 86"));
  reqthrow(p_foo.parse("foo = 86 "));

  // Test string parsing
  CfgParameter<std::string> p_bar("bar", "defstr");
  require(std::string(p_bar) == "defstr");

  require(p_bar.parse("bar = 'Foo'"));
  require(std::string(p_bar) == "Foo");
  require(p_bar.parse("bar = 'Foo\"bar'"));
  require(std::string(p_bar) == "Foo\"bar");
  require(p_bar.parse("bar = \"Foo'bar\""));
  require(std::string(p_bar) == "Foo'bar");

  // Test malformed lines
  reqthrow(p_bar.parse("bar = foo"));
  reqthrow(p_bar.parse("bar = 'foo' "));
}

void test_cfgparser()
{
  CfgParameter<size_t> parm_size("size", 41);
  CfgParameter<size_t> parm_size_def("size_def", 42);
  CfgParameter<std::string> parm_str("str", "foo");
  CfgParameter<std::string> parm_str_def("str_def", "foo");

  CfgParser cfgp("test_cfgparser.0.conf", {
      &parm_size, &parm_size_def,
      &parm_str, &parm_str_def });

  // Test defaults
  require(parm_size == 41);
  require(parm_size_def == 42);
  require(std::string(parm_str) == "foo");
  require(std::string(parm_str_def) == "foo");

  // Reload
  cfgp.reload();

  // Test defaults and updated values
  require(parm_size == 100);
  require(parm_size_def == 42);
  require(std::string(parm_str) == "bar");
  require(std::string(parm_str_def) == "foo");

}
