diff --git a/core/idl_types.h b/core/idl_types.h index f38ff83..57f52bb 100644 --- a/core/idl_types.h +++ b/core/idl_types.h @@ -21,6 +21,7 @@ struct IDLBoolean final : public IDLBaseHelper {}; struct IDLByte final : public IDLBaseHelper {}; +struct IDLFloat final : public IDLBaseHelper {}; struct IDLDouble final : public IDLBaseHelper {}; struct IDLLongLong final : public IDLBaseHelper {}; struct IDLLong final : public IDLBaseHelper {}; diff --git a/core/js_type_traits.h b/core/js_type_traits.h index 2e4c397..cd1ec31 100644 --- a/core/js_type_traits.h +++ b/core/js_type_traits.h @@ -53,6 +53,7 @@ JS_TYPE_TRAITS_NUMBER(int32_t); JS_TYPE_TRAITS_NUMBER(uint32_t); JS_TYPE_TRAITS_NUMBER(int64_t); JS_TYPE_TRAITS_NUMBER(uint64_t); +JS_TYPE_TRAITS_NUMBER(float); JS_TYPE_TRAITS_NUMBER(double); JS_TYPE_TRAITS_BOOLEAN(bool); diff --git a/core/native_type_traits.h b/core/native_type_traits.h index 78b76da..6ced79b 100644 --- a/core/native_type_traits.h +++ b/core/native_type_traits.h @@ -80,6 +80,25 @@ struct NativeTypeTraits : public NativeTypeTraitsBase { } }; +// The double type is a floating point numeric type that corresponds to the set +// of finite double-precision 64 bit IEEE 754 floating point numbers. +template <> +struct NativeTypeTraits : public NativeTypeTraitsBase { + static float NativeValue(const Napi::Env& env, const Napi::Value& js_value) { + if (!js_value.IsNumber()) { + Napi::TypeError::New(env, "It's an invalid number.") + .ThrowAsJavaScriptException(); + return 0.0f; + } + + return js_value.ToNumber().FloatValue(); + } + + static bool IsTypeEquals(const Napi::Value& js_value) { + return js_value.IsNumber(); + } +}; + // The double type is a floating point numeric type that corresponds to the set // of finite double-precision 64 bit IEEE 754 floating point numbers. template <> diff --git a/test/interface_basic_types.test.ts b/test/interface_basic_types.test.ts index 9c2c9dc..21800eb 100644 --- a/test/interface_basic_types.test.ts +++ b/test/interface_basic_types.test.ts @@ -83,7 +83,7 @@ test('Test for IDL \'long long\' type', async () => { // TypeScript's range. expect(test_interface.longLongMethod(0)).toBe(0); - for (var i = Number.MIN_SAFE_INTEGER; i < Number.MAX_SAFE_INTEGER; + for (let i = Number.MIN_SAFE_INTEGER; i < Number.MAX_SAFE_INTEGER; i += Math.floor(Math.random() * Number.MAX_SAFE_INTEGER / 1000)) { expect(test_interface.longLongMethod(i)).toBe(i); } @@ -133,30 +133,93 @@ test('Test for IDL \'unsigned long long\' type', async () => { // So we are not able to do overflow test and so on. expect(test_interface.unsignedLongLongMethod(0)).toBe(0); - for (var i = 1; i < Number.MAX_SAFE_INTEGER; + for (let i = 1; i < Number.MAX_SAFE_INTEGER; i += Math.floor(Math.random() * Number.MAX_SAFE_INTEGER / 1000)) { expect(test_interface.unsignedLongLongMethod(i)).toBe(i); } expect(test_interface.unsignedLongLongMethod(-1) != -1).toBe(true); }); +test('Test for IDL \'float\' type', async () => { + let test_interface = new bacardi.TestInterface(); + + // The float type is a floating point numeric type that corresponds to the set + // of finite single-precision 32 bit IEEE 754 floating point numbers. + + expect(test_interface.floatMethod(0.0)).toBe(0.0); + + const base = 1 / 2; + const precision = 23; + for (let test_case = 0; test_case < 100; test_case++) { + // for fraction part + // create a random number that has 23 bits precision + let fraction = 1; // set the biggest bit. + for (let i = 1; i < precision; i++) { + if (Math.random() > 0.5) + fraction += base ** i; + } + fraction += base ** precision // set the smallest bit + + // for exponent part + // test all value of exponent part + // because exponent value -127 is used to express 0 + // so this must start from -126. + for (let i = -126; i <= 127; i++) { + let float_value = fraction * (2 ** i); + expect(test_interface.floatMethod(float_value)).toBe(float_value); + } + + // these two cases are beyond the range of floating-point + let float_value = fraction * (2 ** -127); + expect(test_interface.floatMethod(float_value) != float_value).toBe(true); + float_value = fraction * (2 ** 128); + expect(test_interface.floatMethod(float_value) != float_value).toBe(true); + } + + let float_min = 2 ** (-149); + ; + expect(test_interface.floatMethod(float_min)).toBe(float_min); + // the value beyond the range of exponent + expect(test_interface.floatMethod(float_min / 2) != float_min / 2).toBe(true); + expect(test_interface.floatMethod(float_min / 2) != float_min / 2).toBe(true); +}); + test('Test for IDL \'double\' type', async () => { let test_interface = new bacardi.TestInterface(); // The double type is a floating point numeric type that corresponds to the // set of finite double-precision 64 bit IEEE 754 floating point numbers. + expect(test_interface.doubleMethod(0.123456789012345)) .toBe(0.123456789012345); - // FIXME(zino): We should test for comparing single-precision floating point. - - // FIXME(zino): We should check whether the type is restricted or - // unrestricted. + const base = 1 / 2; + const precision = 52; + for (let test_case = 0; test_case < 100; test_case++) { + // for fraction part + // create a random number that has 52 bits precision + let fraction = 1; // set the biggest bit. + for (let i = 1; i < precision; i++) { + if (Math.random() > 0.5) + fraction += base ** i; + } + fraction += base ** precision; // set the smallest bit + + // for exponent part + // test all value of exponent part + // because exponent value -1022 is used to express 0 + // so this must start from -1022. + for (let i = -1022; i <= 1023; i += Math.ceil(Math.random() * 100)) { + let double_value = fraction * (2 ** i); + expect(test_interface.doubleMethod(double_value)).toBe(double_value); + } + // Note that the range of double and the range of number in typescript is + // the same, so we can not test the value out of the range. }); test('Test for IDL \'string\' type', async () => { let test_interface = new bacardi.TestInterface(); - + // The string type is not exact matching WebIDL spec but it will convert // UTF8 string in platform side. expect(test_interface.stringMethod('Hello World!')).toBe('Hello World!'); diff --git a/test/test_interface.cc b/test/test_interface.cc index 0431896..ede3a80 100644 --- a/test/test_interface.cc +++ b/test/test_interface.cc @@ -86,6 +86,10 @@ uint64_t TestInterface::UnsignedLongLongMethod(uint64_t number) { return number; } +float TestInterface::FloatMethod(float number) { + return number; +} + double TestInterface::DoubleMethod(double number) { return number; } diff --git a/test/test_interface.h b/test/test_interface.h index 5e6f4fe..fdbbf00 100644 --- a/test/test_interface.h +++ b/test/test_interface.h @@ -41,6 +41,7 @@ class TestInterface { uint16_t UnsignedShortMethod(uint16_t number); uint32_t UnsignedLongMethod(uint32_t number); uint64_t UnsignedLongLongMethod(uint64_t number); + float FloatMethod(float number); double DoubleMethod(double number); const std::string StringMethod(const std::string& string); diff --git a/test/test_interface.idl b/test/test_interface.idl index 9424809..16eac16 100644 --- a/test/test_interface.idl +++ b/test/test_interface.idl @@ -37,6 +37,7 @@ interface TestInterface { unsigned short unsignedShortMethod(unsigned short number); unsigned long unsignedLongMethod(unsigned long number); unsigned long long unsignedLongLongMethod(unsigned long long number); + float floatMethod(float number); double doubleMethod(double number); string stringMethod(string string);