// Copyright (c) 2026 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <FSD_BinaryFile.hxx>

#include <cstring>

#include <gtest/gtest.h>

namespace
{

// Reference for size_t inversion depending on sizeof(size_t).
template <int size>
inline const unsigned char* SizeRef();

template <>
[[maybe_unused]] inline const unsigned char* SizeRef<8>()
{
  static const unsigned char aSizeRef[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  return aSizeRef;
}

template <>
[[maybe_unused]] inline const unsigned char* SizeRef<4>()
{
  static const unsigned char aSizeRef[] = {
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
    0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07,
    0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00};
  return aSizeRef;
}

} // namespace

// OCC24537: GCC compiler warnings in byte order reversion code.
// Tests correctness of InverseInt, InverseReal, InverseShortReal, InverseSize
// on a little-endian platform.

TEST(FSD_BinaryFileTest, OCC24537_InverseInt_Sequential)
{
  const unsigned char anIntRef[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
                                    0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05,
                                    0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
                                    0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00};
  const int           anIntArr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};

  int anInv[10];
  for (int i = 0; i < 10; ++i)
  {
    anInv[i] = FSD_BinaryFile::InverseInt(anIntArr[i]);
  }

  EXPECT_EQ(0, memcmp(anInv, anIntRef, sizeof(anIntRef)));
}

TEST(FSD_BinaryFileTest, OCC24537_InverseInt_Random)
{
  const unsigned char aRndIntRef[] = {0xFF, 0xC2, 0xF7, 0x00, 0xFF, 0xFF, 0xFB, 0x2E, 0x00, 0x00,
                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0xD2,
                                      0x00, 0x00, 0x04, 0xD3, 0xFF, 0xFF, 0xFD, 0x1E, 0xFF, 0xFF,
                                      0xFF, 0xFB, 0x00, 0x00, 0x03, 0x8D, 0x00, 0x3D, 0x09, 0x00};
  const int           aRndIntArr[] = {-4000000, -1234, 0, 1, 1234, 1235, -738, -5, 909, 4000000};

  int anInv[10];
  for (int i = 0; i < 10; ++i)
  {
    anInv[i] = FSD_BinaryFile::InverseInt(aRndIntArr[i]);
  }

  EXPECT_EQ(0, memcmp(anInv, aRndIntRef, sizeof(aRndIntRef)));
}

TEST(FSD_BinaryFileTest, OCC24537_InverseReal_Sequential)
{
  const unsigned char aRealRef[] = {
    0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x40, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x40, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x40, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  const double aRealArr[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 0.0};

  double anInv[10];
  for (int i = 0; i < 10; ++i)
  {
    anInv[i] = FSD_BinaryFile::InverseReal(aRealArr[i]);
  }

  EXPECT_EQ(0, memcmp(anInv, aRealRef, sizeof(aRealRef)));
}

TEST(FSD_BinaryFileTest, OCC24537_InverseReal_Random)
{
  const unsigned char aRndRealRef[] = {
    0xFE, 0x37, 0xE4, 0x3C, 0x88, 0x00, 0x75, 0x9C, 0xBE, 0x11, 0x2E, 0x0B, 0xE8, 0x26, 0xD6, 0x95,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x11, 0x2E, 0x0B, 0xE8, 0x26, 0xD6, 0x95,
    0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x09, 0x21, 0xDA, 0x45, 0x5B, 0x53, 0xE4,
    0x54, 0xB2, 0x49, 0xAD, 0x25, 0x94, 0xC3, 0x7D, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xC0, 0x23, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD, 0x40, 0x23, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD};
  const double aRndRealArr[] = {-1e300, -1.e-9, 0., 1.e-9, 1., 3.1415296, 1.e100, 8.0, -9.9, 9.9};

  double anInv[10];
  for (int i = 0; i < 10; ++i)
  {
    anInv[i] = FSD_BinaryFile::InverseReal(aRndRealArr[i]);
  }

  EXPECT_EQ(0, memcmp(anInv, aRndRealRef, sizeof(aRndRealRef)));
}

TEST(FSD_BinaryFileTest, OCC24537_InverseShortReal_Sequential)
{
  const unsigned char aShortRealRef[] = {
    0x3F, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x80,
    0x00, 0x00, 0x40, 0xA0, 0x00, 0x00, 0x40, 0xC0, 0x00, 0x00, 0x40, 0xE0, 0x00, 0x00,
    0x41, 0x00, 0x00, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  const float aShortRealArr[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 0.0f};

  float anInv[10];
  for (int i = 0; i < 10; ++i)
  {
    anInv[i] = FSD_BinaryFile::InverseShortReal(aShortRealArr[i]);
  }

  EXPECT_EQ(0, memcmp(anInv, aShortRealRef, sizeof(aShortRealRef)));
}

TEST(FSD_BinaryFileTest, OCC24537_InverseShortReal_Random)
{
  const unsigned char aRndShortRealRef[] = {
    0xB0, 0x89, 0x70, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x30, 0x89, 0x70, 0x5F, 0x3F, 0x80,
    0x00, 0x00, 0x40, 0x49, 0x0E, 0x56, 0xC0, 0xD6, 0x66, 0x66, 0x40, 0xD6, 0x66, 0x66,
    0x42, 0xC5, 0xCC, 0xCD, 0xC2, 0xC7, 0xCC, 0xCD, 0x42, 0xC7, 0xCC, 0xCD};
  const float aRndShortRealArr[] =
    {-1.e-9f, 0.f, 1.e-9f, 1.f, 3.1415f, -6.7f, 6.7f, 98.9f, -99.9f, 99.9f};

  float anInv[10];
  for (int i = 0; i < 10; ++i)
  {
    anInv[i] = FSD_BinaryFile::InverseShortReal(aRndShortRealArr[i]);
  }

  EXPECT_EQ(0, memcmp(anInv, aRndShortRealRef, sizeof(aRndShortRealRef)));
}

TEST(FSD_BinaryFileTest, OCC24537_InverseSize_Sequential)
{
  const size_t         aSizeArr[] = {1ul, 2ul, 3ul, 4ul, 5ul, 6ul, 7ul, 8ul, 9ul, 0ul};
  const unsigned char* aSizeRef   = SizeRef<sizeof(size_t)>();

  size_t anInv[10];
  for (int i = 0; i < 10; ++i)
  {
    anInv[i] = FSD_BinaryFile::InverseSize(aSizeArr[i]);
  }

  EXPECT_EQ(0, memcmp(anInv, aSizeRef, sizeof(size_t) * 10));
}
