text: /*=========================================================================
   *
   *  Copyright Insight Software Consortium
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *         http://www.apache.org/licenses/LICENSE-2.0.txt
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   *=========================================================================*/
  
  #include "itkMetaImageIO.h"
  
  #include "itkImageIOFactory.h" // required to instantiate an instance of ImageIOBase
  
  // Specific ImageIO test
  
  // Macro to check that two arrays have the same size at compile time. It doesn't compile if they don't
  // as it tries to create an array of size(-1)
  // https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/
  #define CHECK_ARRAYS_HAVE_SAME_SIZE_AT_COMPILE_TIME(array1, array2)                                                    \
    ((void)sizeof(char[1 - 2 * !!(sizeof(array1) / sizeof(*array1) - sizeof(array2) / sizeof(*array2))]))
  
  int
  itkImageIOBaseTest(int, char *[])
  {
    itk::MetaImageIO::Pointer reader = itk::MetaImageIO::New();
    reader->SetNumberOfDimensions(3);
  
    bool gotException = false;
    try
    {
      reader->SetDimensions(3, 1);
    }
    catch (itk::ExceptionObject & e)
    {
      std::cerr << "Caught expected exception " << e << std::endl;
      gotException = true;
    }
    if (!gotException)
    {
      std::cerr << "Failed to catch expected exception in method SetDimensions" << std::endl;
      return EXIT_FAILURE;
    }
  
    gotException = false;
    try
    {
      reader->SetOrigin(3, 1.0);
    }
    catch (itk::ExceptionObject & e)
    {
      std::cerr << "Caught expected exception " << e << std::endl;
      gotException = true;
    }
    if (!gotException)
    {
      std::cerr << "Failed to catch expected exception in method SetOrigin" << std::endl;
      return EXIT_FAILURE;
    }
  
    gotException = false;
    try
    {
      reader->SetSpacing(3, 1.0);
    }
    catch (itk::ExceptionObject & e)
    {
      std::cerr << "Caught expected exception " << e << std::endl;
      gotException = true;
    }
    if (!gotException)
    {
      std::cerr << "Failed to catch expected exception in method SetSpacing" << std::endl;
      return EXIT_FAILURE;
    }
  
    gotException = false;
    try
    {
      std::vector<double> direction(3);
      direction[0] = 1.0;
      direction[1] = 1.0;
      direction[2] = 1.0;
      reader->SetDirection(3, direction);
    }
    catch (itk::ExceptionObject & e)
    {
      std::cerr << "Caught expected exception " << e << std::endl;
      gotException = true;
    }
    if (!gotException)
    {
      std::cerr << "Failed to catch expected exception in method SetDirection" << std::endl;
      return EXIT_FAILURE;
    }
  
    gotException = false;
    try
    {
      vnl_vector<double> direction(3);
      direction[0] = 1.0;
      direction[1] = 1.0;
      direction[2] = 1.0;
      reader->SetDirection(3, direction);
    }
    catch (itk::ExceptionObject & e)
    {
      std::cerr << "Caught expected exception " << e << std::endl;
      gotException = true;
    }
    if (!gotException)
    {
      std::cerr << "Failed to catch expected exception in method SetDirection" << std::endl;
      return EXIT_FAILURE;
    }
    { // Test string <-> type conversions
      itk::ImageIOBase::IOComponentType listComponentType[] = { itk::ImageIOBase::UNKNOWNCOMPONENTTYPE,
                                                                itk::ImageIOBase::UCHAR,
                                                                itk::ImageIOBase::CHAR,
                                                                itk::ImageIOBase::USHORT,
                                                                itk::ImageIOBase::SHORT,
                                                                itk::ImageIOBase::UINT,
                                                                itk::ImageIOBase::INT,
                                                                itk::ImageIOBase::ULONG,
                                                                itk::ImageIOBase::LONG,
                                                                itk::ImageIOBase::ULONGLONG,
                                                                itk::ImageIOBase::LONGLONG,
                                                                itk::ImageIOBase::FLOAT,
                                                                itk::ImageIOBase::DOUBLE };
      const char * listComponentTypeString[] = { "unknown", "unsigned_char",      "char",      "unsigned_short",
                                                 "short",   "unsigned_int",       "int",       "unsigned_long",
                                                 "long",    "unsigned_long_long", "long_long", "float",
                                                 "double" };
      itk::ImageIOBase::IOPixelType listIOPixelType[] = { itk::ImageIOBase::UNKNOWNPIXELTYPE,
                                                          itk::ImageIOBase::SCALAR,
                                                          itk::ImageIOBase::RGB,
                                                          itk::ImageIOBase::RGBA,
                                                          itk::ImageIOBase::OFFSET,
                                                          itk::ImageIOBase::VECTOR,
                                                          itk::ImageIOBase::POINT,
                                                          itk::ImageIOBase::COVARIANTVECTOR,
                                                          itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR,
                                                          itk::ImageIOBase::DIFFUSIONTENSOR3D,
                                                          itk::ImageIOBase::COMPLEX,
                                                          itk::ImageIOBase::FIXEDARRAY,
                                                          itk::ImageIOBase::MATRIX };
      const char *                  listIOPixelTypeString[] = { "unknown",
                                               "scalar",
                                               "rgb",
                                               "rgba",
                                               "offset",
                                               "vector",
                                               "point",
                                               "covariant_vector",
                                               "symmetric_second_rank_tensor",
                                               "diffusion_tensor_3D",
                                               "complex",
                                               "fixed_array",
                                               "matrix" };
      CHECK_ARRAYS_HAVE_SAME_SIZE_AT_COMPILE_TIME(listComponentTypeString, listComponentType);
      CHECK_ARRAYS_HAVE_SAME_SIZE_AT_COMPILE_TIME(listIOPixelType, listIOPixelTypeString);
      size_t listComponentSize = sizeof(listComponentType) / sizeof(*listComponentType);
      size_t listPixelSize = sizeof(listIOPixelType) / sizeof(*listIOPixelType);
      { // Test the static version of the string <-> type conversions
        for (size_t i = 0; i < listComponentSize; ++i)
        {
          std::string componentTypeString = itk::ImageIOBase::GetComponentTypeAsString(listComponentType[i]);
          if (componentTypeString.compare(listComponentTypeString[i]) != 0)
          {
            std::cerr << "GetComponentTypeAsString(" << listComponentType[i] << ") should return '"
                      << listComponentTypeString[i] << "'" << std::endl;
            return EXIT_FAILURE;
          }
        }
        for (size_t i = 0; i < listPixelSize; ++i)
        {
          std::string pixelTypeString = itk::ImageIOBase::GetPixelTypeAsString(listIOPixelType[i]);
          if (pixelTypeString.compare(listIOPixelTypeString[i]) != 0)
          {
            std::cerr << "GetPixelTypeAsString(" << listIOPixelType[i] << ") should return '" << listIOPixelTypeString[i]
                      << "'" << std::endl;
            return EXIT_FAILURE;
          }
        }
        for (size_t i = 0; i < listComponentSize; ++i)
        {
          itk::ImageIOBase::IOComponentType componentType =
            itk::ImageIOBase::GetComponentTypeFromString(listComponentTypeString[i]);
          if (componentType != listComponentType[i])
          {
            std::cerr << "GetComponentTypeFromString('" << listComponentTypeString[i] << "') should return "
                      << listComponentType[i] << std::endl;
            return EXIT_FAILURE;
          }
        }
        for (size_t i = 0; i < listPixelSize; ++i)
        {
          itk::ImageIOBase::IOPixelType pixelType = itk::ImageIOBase::GetPixelTypeFromString(listIOPixelTypeString[i]);
          if (pixelType != listIOPixelType[i])
          {
            std::cerr << "GetPixelTypeFromString('" << listIOPixelTypeString[i] << "') should return "
                      << listIOPixelType[i] << std::endl;
            return EXIT_FAILURE;
          }
        }
      } // end Test the static version of the string <-> type conversions
  
      // Test the non-static version of the string <-> type conversions
      {
        // Create an instance of ImageIOBase. It does not matter that 'test' is not a valid image to read,
        // we just want the ImageIOBase object.
        itk::ImageIOBase::Pointer imageIOBase =
          itk::ImageIOFactory::CreateImageIO("test", itk::ImageIOFactory::FileModeType::ReadMode);
        for (size_t i = 0; i < listComponentSize; ++i)
        {
          std::string componentTypeString = imageIOBase->GetComponentTypeAsString(listComponentType[i]);
          if (componentTypeString.compare(listComponentTypeString[i]) != 0)
          {
            std::cerr << "GetComponentTypeAsString(" << listComponentType[i] << ") should return '"
                      << listComponentTypeString[i] << "'" << std::endl;
            return EXIT_FAILURE;
          }
        }
        for (size_t i = 0; i < listPixelSize; ++i)
        {
          std::string pixelTypeString = imageIOBase->GetPixelTypeAsString(listIOPixelType[i]);
          if (pixelTypeString.compare(listIOPixelTypeString[i]) != 0)
          {
            std::cerr << "GetPixelTypeAsString(" << listIOPixelType[i] << ") should return " << listIOPixelTypeString[i]
                      << std::endl;
            return EXIT_FAILURE;
          }
        }
        for (size_t i = 0; i < listComponentSize; ++i)
        {
          itk::ImageIOBase::IOComponentType componentType =
            imageIOBase->GetComponentTypeFromString(listComponentTypeString[i]);
          if (componentType != listComponentType[i])
          {
            std::cerr << "GetComponentTypeFromString('" << listComponentTypeString[i] << "') should return "
                      << listComponentType[i] << std::endl;
            return EXIT_FAILURE;
          }
        }
        for (size_t i = 0; i < listPixelSize; ++i)
        {
          itk::ImageIOBase::IOPixelType pixelType = imageIOBase->GetPixelTypeFromString(listIOPixelTypeString[i]);
          if (pixelType != listIOPixelType[i])
          {
            std::cerr << "GetPixelTypeFromString('" << listIOPixelTypeString[i] << "') should return "
                      << listIOPixelType[i] << std::endl;
            return EXIT_FAILURE;
          }
        }
      } // end Test the non-static version of the string <-> type conversions
    }
    return EXIT_SUCCESS;
  }
  