import StdlibUnittest

%{
import gyb
from SwiftFloatingPointTypes import all_floating_point_types, getFtoIBounds
from SwiftIntTypes import all_integer_types
}%

var FixedPointConversionTruncations = TestSuite("FixedPointToFloatingPointConversionTruncations")
var FixedPointConversionFailures = TestSuite("FixedPointToFloatingPointConversionFailures")

var FloatingPointConversionTruncations = TestSuite("FloatingPointToFloatingPointConversionTruncations")
var FloatingPointConversionFailures = TestSuite("FloatingPointToFloatingPointConversionFailures")

%  for self_type in all_floating_point_types():
%   SelfSignificandBits = self_type.bits
%   Self = self_type.stdlib_name

%  if Self == 'Float16':
#if !os(macOS) && !(os(iOS) && targetEnvironment(macCatalyst))
%  end
%  if Self == 'Float80':
#if !os(Windows) && (arch(i386) || arch(x86_64))
%  end

%  for other_type in all_floating_point_types():
%   OtherSignificandBits = other_type.bits
%   OtherFloat = other_type.stdlib_name

%   if OtherFloat == 'Float16':
#if !os(macOS) && !(os(iOS) && targetEnvironment(macCatalyst))
%   end
%   if OtherFloat == 'Float80':
#if !os(Windows) && (arch(i386) || arch(x86_64))
%   end

%   if OtherSignificandBits <= SelfSignificandBits:

%    if OtherFloat == 'Float16':
if #available(iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
%    end
FloatingPointConversionTruncations.test("${OtherFloat}To${Self}Conversion")

  .forEach(in: [
     ${OtherFloat}.greatestFiniteMagnitude,
    -${OtherFloat}.greatestFiniteMagnitude,
     (1.0 as ${OtherFloat}).nextUp,
     (1.0 as ${OtherFloat}).nextDown,
    (-1.0 as ${OtherFloat}).nextUp,
    (-1.0 as ${OtherFloat}).nextDown,
  ]) {
  input in
  // FIXME: we should have a stronger postcondition here.
  let result = ${Self}(input)
  let resultConvertedBack = ${OtherFloat}(result)
  expectEqual(input, resultConvertedBack)
}
%    if OtherFloat == 'Float16':
}
%    end

%   else:

%    if Self == 'Float16':
if #available(iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
%    end
FloatingPointConversionTruncations.test("${OtherFloat}To${Self}Conversion")
  .forEach(in: [
    ( ${OtherFloat}.greatestFiniteMagnitude,  ${Self}.infinity),
    (-${OtherFloat}.greatestFiniteMagnitude, -${Self}.infinity),
    ( (1.0 as ${OtherFloat}).nextUp,    1.0 as ${Self}),
    ( (1.0 as ${OtherFloat}).nextDown,  1.0 as ${Self}),
    ((-1.0 as ${OtherFloat}).nextUp,   -1.0 as ${Self}),
    ((-1.0 as ${OtherFloat}).nextDown, -1.0 as ${Self}),
  ]) {
  (input, expectedResult) in
  expectEqual(expectedResult, ${Self}(input))
}
%    if Self == 'Float16':
}
%    end

%   end

%    if 'Float16' in [Self, OtherFloat]:
if #available(iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
%    end
FloatingPointConversionTruncations.test("${OtherFloat}To${Self}Conversion/special") {
  expectEqual( 1.0 as ${Self},   ${Self}(exactly:  1.0 as ${OtherFloat}))
  expectEqual(-1.0 as ${Self},   ${Self}(exactly: -1.0 as ${OtherFloat}))
  expectEqual( ${Self}.infinity, ${Self}( ${OtherFloat}.infinity))
  expectEqual(-${Self}.infinity, ${Self}(-${OtherFloat}.infinity))
  expectTrue(${Self}(${OtherFloat}.nan).isNaN)
}

FloatingPointConversionFailures.test("${OtherFloat}To${Self}FailableConversion")
  .forEach(in: [
    ${OtherFloat}.greatestFiniteMagnitude,
    -${OtherFloat}.greatestFiniteMagnitude,
    (1.0 as ${OtherFloat}).nextUp,
    (1.0 as ${OtherFloat}).nextDown,
    (-1.0 as ${OtherFloat}).nextUp,
    (-1.0 as ${OtherFloat}).nextDown,
  ]) {
  input in
  let result = ${Self}(exactly: input)
%   if OtherSignificandBits <= SelfSignificandBits:
  if let result = expectNotNil(result) {
    // FIXME: we should have a stronger postcondition here.
    expectEqual(input, ${OtherFloat}(result))
  }
%   else:
  expectNil(result)
%   end
}

FloatingPointConversionFailures.test("${OtherFloat}To${Self}Conversion/AlwaysSuccess") {
  expectEqual( 1.0 as ${Self},   ${Self}(exactly:  1.0 as ${OtherFloat}))
  expectEqual(-1.0 as ${Self},   ${Self}(exactly: -1.0 as ${OtherFloat}))
  expectEqual( ${Self}.infinity, ${Self}(exactly:  ${OtherFloat}.infinity))
  expectEqual(-${Self}.infinity, ${Self}(exactly: -${OtherFloat}.infinity))
  expectNil(${Self}(exactly: ${OtherFloat}.nan))
}
%    if 'Float16' in [Self, OtherFloat]:
}
%    end

%  if OtherFloat == 'Float16':
#endif
%  end
%   if OtherFloat == 'Float80':
#endif
%   end

%  end # for in all_floating_point_types (Other)

#if arch(i386) || arch(arm)
% int_types = all_integer_types(32)
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
% int_types = all_integer_types(64)
#else
_UnimplementedError()
#endif

% for int_ty in int_types:
%  OtherInt = int_ty.stdlib_name

extension ${OtherInt} {
  %    if Self == 'Float16':
  @available(iOS 14.0, watchOS 7.0, tvOS 14.0, *)
  @available(macOS, unavailable)
  %    end
  static var _test${Self}Conversion: [(${OtherInt}, ${OtherInt}, ${OtherInt}?)] {
    if bitWidth > ${Self}.significandBitCount + 1 {
      let bitOffset = ${Self}.significandBitCount + 1
      let limit: ${OtherInt} = ~(~0 << bitOffset)
      let over: ${OtherInt} = 1 + limit << 1
      return [
        (0, 0, 0),
        (limit, limit, limit),
        (over, over + 1, nil),
%   if int_ty.is_signed:
        (-limit, -limit, -limit),
        (-over, -(over + 1), nil),
%   end
      ]
    } else {
      return [
        (0, 0, 0),
        (.min, .min, .min),
        (.max, .max, .max),
      ]
    }
  }
}

%    if Self == 'Float16':
if #available(iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
%    end
FixedPointConversionTruncations.test("${OtherInt}to${Self}")
  .forEach(in: ${OtherInt}._test${Self}Conversion) {
    value, roundedExpectation, exactExpectation in

  let roundedResult = ${Self}(value)
  expectEqual(roundedResult, ${Self}(roundedExpectation))

  let exactResult = ${Self}(exactly: value)
  if let expectation = exactExpectation {
    expectEqual(exactResult!, ${Self}(expectation))
  } else {
    expectNil(exactResult)
  }
}
%    if Self == 'Float16':
}
%    end

%  end # for in int_types

%  if Self == 'Float16':
#endif
%  end
%  if Self == 'Float80':
#endif
%  end

% end # for in all_floating_point_types (Self)

runAllTests()
