/*
 * Author:          Patrick-Christopher Mattulat
 * Co-Author:       Claude Sonnet 4.6 (LLM)
 * Company:         Lynar Studios
 * E-Mail:          webmaster@lynarstudios.com
 * Created:         2020-08-17
 * Changed:         2026-06-23
 *
 * */

#include <gtest/gtest.h>
#include <ls-std/ls-std-boxing.hpp>
#include <ls-std/ls-std-core.hpp>

using ls::standard::boxing::Long;
using ls::standard::core::IllegalArithmeticOperationException;
using ls::standard::core::type::long_type;
using testing::Test;

namespace
{
  class LongTest : public Test
  {
    public:

      LongTest() = default;
      ~LongTest() override = default;
  };

  // assignment operators

  TEST_F(LongTest, operator_assignment_with_reference)
  {
    Long x{13};
    const Long y{3};
    x = y;

    ASSERT_EQ(3, x.getValue());
  }

  TEST_F(LongTest, operator_assignment_with_value)
  {
    Long x{13};
    x = 3;

    ASSERT_EQ(3, x.getValue());
  }

  // arithmetic operators

  TEST_F(LongTest, operator_negative)
  {
    const Long x{13};
    const Long y{-13};

    ASSERT_EQ(-13, -x);
    ASSERT_EQ(13, -y);
  }

  TEST_F(LongTest, operator_add_with_reference)
  {
    const Long x{13};
    const Long y{7};

    ASSERT_EQ(20, x + y);
  }

  TEST_F(LongTest, operator_add_with_value)
  {
    const Long x{13};
    ASSERT_EQ(20, x + 7);
  }

  TEST_F(LongTest, operator_mul_with_reference)
  {
    const Long x{3};
    const Long y{7};

    ASSERT_EQ(21, x * y);
  }

  TEST_F(LongTest, operator_mul_with_value)
  {
    const Long x{3};
    ASSERT_EQ(21, x * 7);
  }

  TEST_F(LongTest, operator_sub_with_reference)
  {
    const Long x{51};
    const Long y{17};

    ASSERT_EQ(34, x - y);
  }

  TEST_F(LongTest, operator_sub_with_value)
  {
    const Long x{51};
    ASSERT_EQ(34, x - 17);
  }

  TEST_F(LongTest, operator_div_with_reference)
  {
    const Long x{81};
    const Long y{9};

    ASSERT_EQ(9, x / y);
  }

  TEST_F(LongTest, operator_div_with_value)
  {
    const Long x{81};
    ASSERT_EQ(9, x / 9);
  }

  TEST_F(LongTest, operator_div_by_zero_with_reference)
  {
    EXPECT_THROW(
        {
          try
          {
            Long x{9};
            Long y{0};

            x = x / y;
          }
          catch (const IllegalArithmeticOperationException &_exception)
          {
            throw;
          }
        },
        IllegalArithmeticOperationException);
  }

  TEST_F(LongTest, operator_div_by_zero_with_value)
  {
    EXPECT_THROW(
        {
          try
          {
            Long x{9};
            x = x / 0;
          }
          catch (const IllegalArithmeticOperationException &_exception)
          {
            throw;
          }
        },
        IllegalArithmeticOperationException);
  }

  TEST_F(LongTest, operator_mod_with_reference)
  {
    const Long x{85};
    const Long y{9};

    ASSERT_EQ(4, x % y);
  }

  TEST_F(LongTest, operator_mod_with_value)
  {
    const Long x{85};
    ASSERT_EQ(4, x % 9);
  }

  // compound operators

  TEST_F(LongTest, operator_add_equals_with_reference)
  {
    Long x{4};
    const Long y{2};
    x += y;

    ASSERT_EQ(6, x.getValue());
  }

  TEST_F(LongTest, operator_add_equals_with_value)
  {
    Long x{4};
    x += 2;

    ASSERT_EQ(6, x.getValue());
  }

  TEST_F(LongTest, operator_sub_equals_with_reference)
  {
    Long x{14};
    const Long y{2};
    x -= y;

    ASSERT_EQ(12, x.getValue());
  }

  TEST_F(LongTest, operator_sub_equals_with_value)
  {
    Long x{14};
    x -= 2;

    ASSERT_EQ(12, x.getValue());
  }

  TEST_F(LongTest, operator_mul_equals_with_reference)
  {
    Long x{6};
    const Long y{3};
    x *= y;

    ASSERT_EQ(18, x.getValue());
  }

  TEST_F(LongTest, operator_mul_equals_with_value)
  {
    Long x{6};
    x *= 3;

    ASSERT_EQ(18, x.getValue());
  }

  TEST_F(LongTest, operator_div_equals_with_reference)
  {
    Long x{12};
    const Long y{3};
    x /= y;

    ASSERT_EQ(4, x.getValue());
  }

  TEST_F(LongTest, operator_div_equals_with_value)
  {
    Long x{12};
    x /= 3;

    ASSERT_EQ(4, x.getValue());
  }

  TEST_F(LongTest, operator_div_equals_by_zero_with_reference)
  {
    EXPECT_THROW(
        {
          try
          {
            Long x{9};
            Long y{0};

            x = x /= y;
          }
          catch (const IllegalArithmeticOperationException &_exception)
          {
            throw;
          }
        },
        IllegalArithmeticOperationException);
  }

  TEST_F(LongTest, operator_div_equals_by_zero_with_value)
  {
    EXPECT_THROW(
        {
          try
          {
            Long x{9};
            x = x /= 0;
          }
          catch (const IllegalArithmeticOperationException &_exception)
          {
            throw;
          }
        },
        IllegalArithmeticOperationException);
  }

  // comparison operators

  TEST_F(LongTest, operator_equals_with_reference)
  {
    const Long x{12};
    const Long y{12};

    ASSERT_TRUE(x == y);
  }

  TEST_F(LongTest, operator_equals_with_value)
  {
    const Long x{12};
    ASSERT_TRUE(x == 12);
  }

  TEST_F(LongTest, operator_not_equals_with_reference)
  {
    const Long x{12};
    const Long y{3};

    ASSERT_TRUE(x != y);
  }

  TEST_F(LongTest, operator_not_equals_with_value)
  {
    const Long x{12};
    ASSERT_TRUE(x != 3);
  }

  TEST_F(LongTest, operator_greater_than_with_reference)
  {
    const Long x{12};
    const Long y{3};

    ASSERT_TRUE(x > y);
  }

  TEST_F(LongTest, operator_greater_than_with_value)
  {
    const Long x{12};
    ASSERT_TRUE(x > 3);
  }

  TEST_F(LongTest, operator_greater_than_equals_with_reference)
  {
    const Long x{12};
    const Long y{12};

    ASSERT_TRUE(x >= y);
  }

  TEST_F(LongTest, operator_greater_than_equals_with_value)
  {
    const Long x{12};
    ASSERT_TRUE(x >= 12);
  }

  TEST_F(LongTest, operator_less_than_with_reference)
  {
    const Long x{10};
    const Long y{12};

    ASSERT_TRUE(x < y);
  }

  TEST_F(LongTest, operator_less_than_with_value)
  {
    const Long x{10};
    Long y{12};

    ASSERT_TRUE(x < 12);
  }

  TEST_F(LongTest, operator_less_than_equals_with_reference)
  {
    const Long x{10};
    const Long y{10};

    ASSERT_TRUE(x <= y);
  }

  TEST_F(LongTest, operator_less_than_equals_with_value)
  {
    const Long x{10};
    ASSERT_TRUE(x <= 10);
  }

  // logical operators

  TEST_F(LongTest, operator_negation)
  {
    const Long x{};
    ASSERT_TRUE(!x);
  }

  // increment / decrement operator

  TEST_F(LongTest, operator_increment)
  {
    Long x{};
    ++x;

    ASSERT_EQ(1, x.getValue());
  }

  TEST_F(LongTest, operator_decrement)
  {
    Long x{};
    --x;

    ASSERT_EQ(-1, x.getValue());
  }

  // implementation

  TEST_F(LongTest, parse_with_positive_value)
  {
    Long x{};

    x.parse("1989");
    ASSERT_EQ(1989, x.getValue());
  }

  TEST_F(LongTest, parse_with_negative_value)
  {
    Long x{};

    x.parse("-17");
    ASSERT_EQ(-17, x.getValue());
  }

  TEST_F(LongTest, toString)
  {
    Long x{112};
    ASSERT_STREQ("112", x.toString().c_str());
  }

  // additional functionality

  TEST_F(LongTest, getValue)
  {
    const Long x{3};
    ASSERT_EQ(3, x.getValue());
  }

  // additional testing

  TEST_F(LongTest, constApproach)
  {
    const Long x{3};
    ASSERT_EQ(3, x.getValue());

    // x = 4; // wouldn't work
  }
}
