/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/

#include <usAny.h>

#include "usTestingMacros.h"

#include <limits>

using namespace us;

int usAnyTest(int /*argc*/, char* /*argv*/[])
{
  US_TEST_BEGIN("AnyTest");

  Any empty;
  US_TEST_CONDITION(empty.Empty(), "Default-constructed Any is empty")
  US_TEST_CONDITION(empty.ToString() == "", "Empty Any.ToString() returns empty string")
  US_TEST_CONDITION(empty.ToJSON() == "null", "Empty Any.ToJSON() returns JSON null literal")

  Any anyBool = true;
  US_TEST_CONDITION(anyBool.Type() == typeid(bool), "Any[bool].Type()")
  US_TEST_CONDITION(any_cast<bool>(anyBool) == true, "any_cast<bool>()")
  US_TEST_CONDITION(anyBool.ToString() == "1", "Any[bool].ToString()")
  US_TEST_CONDITION(anyBool.ToJSON() == "true", "Any[bool].ToJSON()")
  anyBool = false;
  US_TEST_CONDITION(anyBool.ToString() == "0", "Any[bool].ToString()")
  US_TEST_CONDITION(anyBool.ToJSON() == "false", "Any[bool].ToJSON()")

  Any anyInt = 13;
  US_TEST_CONDITION(anyInt.Type() == typeid(int), "Any[int].Type()")
  US_TEST_CONDITION(any_cast<int>(anyInt) == 13, "any_cast<int>()")
  US_TEST_CONDITION(anyInt.ToString() == "13", "Any[int].ToString()")
  US_TEST_CONDITION(anyInt.ToJSON() == "13", "Any[int].ToJSON()")

  Any anyChar = 'a';
  US_TEST_CONDITION(anyChar.Type() == typeid(char), "Any[char].Type()")
  US_TEST_CONDITION(any_cast<char>(anyChar) == 'a', "any_cast<char>()")
  US_TEST_CONDITION(anyChar.ToString() == "a", "Any[char].ToString()")
  US_TEST_CONDITION(anyChar.ToJSON() == "a", "Any[char].ToJSON()")

  Any anyFloat = 0.2f;
  US_TEST_CONDITION(anyFloat.Type() == typeid(float), "Any[float].Type()")
  US_TEST_CONDITION(any_cast<float>(anyFloat) - 0.2f < std::numeric_limits<float>::epsilon(), "any_cast<float>()")
  US_TEST_CONDITION(anyFloat.ToString() == "0.2", "Any[float].ToString()")
  US_TEST_CONDITION(anyFloat.ToString() == "0.2", "Any[float].ToJSON()")

  Any anyDouble = 0.5;
  US_TEST_CONDITION(anyDouble.Type() == typeid(double), "Any[double].Type()")
  US_TEST_CONDITION(any_cast<double>(anyDouble) - 0.5 < std::numeric_limits<double>::epsilon(), "any_cast<double>()")
  US_TEST_CONDITION(anyDouble.ToString() == "0.5", "Any[double].ToString()")
  US_TEST_CONDITION(anyDouble.ToString() == "0.5", "Any[double].ToJSON()")

  Any anyString = std::string("hello");
  US_TEST_CONDITION(anyString.Type() == typeid(std::string), "Any[std::string].Type()")
  US_TEST_CONDITION(any_cast<std::string>(anyString) == "hello", "any_cast<std::string>()")
  US_TEST_CONDITION(anyString.ToString() == "hello", "Any[std::string].ToString()")
  US_TEST_CONDITION(anyString.ToJSON() == "\"hello\"", "Any[std::string].ToJSON()")

  std::vector<int> vecInts;
  vecInts.push_back(1);
  vecInts.push_back(2);
  Any anyVectorOfInts = vecInts;
  US_TEST_CONDITION(anyVectorOfInts.Type() == typeid(std::vector<int>), "Any[std::vector<int>].Type()")
  US_TEST_CONDITION(any_cast<std::vector<int> >(anyVectorOfInts) == vecInts, "any_cast<std::vector<int>>()")
  US_TEST_CONDITION(anyVectorOfInts.ToString() == "[1,2]", "Any[std::vector<int>].ToString()")
  US_TEST_CONDITION(anyVectorOfInts.ToJSON() == "[1,2]", "Any[std::vector<int>].ToJSON()")

  std::list<int> listInts;
  listInts.push_back(1);
  listInts.push_back(2);
  Any anyListOfInts = listInts;
  US_TEST_CONDITION(anyListOfInts.Type() == typeid(std::list<int>), "Any[std::list<int>].Type()")
  US_TEST_CONDITION(any_cast<std::list<int> >(anyListOfInts) == listInts, "any_cast<std::list<int>>()")
  US_TEST_CONDITION(anyListOfInts.ToString() == "[1,2]", "Any[std::list<int>].ToString()")
  US_TEST_CONDITION(anyListOfInts.ToJSON() == "[1,2]", "Any[std::list<int>].ToJSON()")

  std::set<int> setInts;
  setInts.insert(1);
  setInts.insert(2);
  Any anySetOfInts = setInts;
  US_TEST_CONDITION(anySetOfInts.Type() == typeid(std::set<int>), "Any[std::set<int>].Type()")
  US_TEST_CONDITION(any_cast<std::set<int> >(anySetOfInts) == setInts, "any_cast<std::set<int>>()")
  US_TEST_CONDITION(anySetOfInts.ToString() == "[1,2]", "Any[std::set<int>].ToString()")
  US_TEST_CONDITION(anySetOfInts.ToJSON() == "[1,2]", "Any[std::set<int>].ToJSON()")

  std::vector<Any> vecAny;
  vecAny.push_back(1);
  vecAny.push_back(std::string("hello"));
  Any anyVectorOfAnys = vecAny;
  US_TEST_CONDITION(anyVectorOfAnys.Type() == typeid(std::vector<Any>), "Any[std::vector<Any>].Type()")
  US_TEST_CONDITION(anyVectorOfAnys.ToString() == "[1,hello]", "Any[std::vector<Any>].ToString()")
  US_TEST_CONDITION(anyVectorOfAnys.ToJSON() == "[1,\"hello\"]", "Any[std::vector<Any>].ToJSON()")

  std::list<Any> listAny;
  listAny.push_back(1);
  listAny.push_back(std::string("hello"));
  Any anyListOfAnys = listAny;
  US_TEST_CONDITION(anyListOfAnys.Type() == typeid(std::list<Any>), "Any[std::list<Any>].Type()")
  US_TEST_CONDITION(anyListOfAnys.ToString() == "[1,hello]", "Any[std::list<Any>].ToString()")
  US_TEST_CONDITION(anyListOfAnys.ToJSON() == "[1,\"hello\"]", "Any[std::list<Any>].ToJSON()")

  std::map<std::string, int> map1;
  map1["one"] = 1;
  map1["two"] = 2;
  Any anyMap1 = map1;
  US_TEST_CONDITION(anyMap1.Type() == typeid(std::map<std::string, int>), "Any[std::map<std::string,int>].Type()")
  US_TEST_CONDITION((any_cast<std::map<std::string, int> >(anyMap1) == map1), "any_cast<std::map<std::string,int>>()")
  US_TEST_CONDITION(anyMap1.ToString() == "{one : 1, two : 2}", "Any[std::map<std::string,int>].ToString()")
  US_TEST_CONDITION(anyMap1.ToJSON() == "{\"one\" : 1, \"two\" : 2}", "Any[std::map<std::string,int>].ToJSON()")

  std::map<int, Any> map2;
  map2[1] = 0.3;
  map2[3] = std::string("bye");
  Any anyMap2 = map2;
  US_TEST_CONDITION(anyMap2.Type() == typeid(std::map<int, Any>), "Any[std::map<int,Any>].Type()")
  US_TEST_CONDITION(anyMap2.ToString() == "{1 : 0.3, 3 : bye}", "Any[std::map<int,Any>].ToString()")
  US_TEST_CONDITION(anyMap2.ToJSON() == "{\"1\" : 0.3, \"3\" : \"bye\"}", "Any[std::map<int,Any>].ToJSON()")

  std::map<std::string, Any> map3;
  map3["number"] = 5;
  std::vector<int> numbers;
  numbers.push_back(9);
  numbers.push_back(8);
  numbers.push_back(7);
  map3["vector"] = numbers;
  map3["map"] = map2;
  Any anyMap3 = map3;
  US_TEST_CONDITION(anyMap3.Type() == typeid(std::map<std::string, Any>), "Any[std::map<std::string,Any>].Type()")
  US_TEST_CONDITION(anyMap3.ToString() == "{map : {1 : 0.3, 3 : bye}, number : 5, vector : [9,8,7]}", "Any[std::map<std::string,Any>].ToString()")
  US_TEST_CONDITION(anyMap3.ToJSON() == "{\"map\" : {\"1\" : 0.3, \"3\" : \"bye\"}, \"number\" : 5, \"vector\" : [9,8,7]}", "Any[std::map<std::string,Any>].ToJSON()")

  US_TEST_END()
}
