THRIFT-4476: Typecasting problem on double list items,
emitting doubles with high precision
Client: cpp
Client: erl
Client: java
Client: js
Client: py

This closes #1511
diff --git a/test/DoubleConstantsTest.thrift b/test/DoubleConstantsTest.thrift
new file mode 100644
index 0000000..c9212ab
--- /dev/null
+++ b/test/DoubleConstantsTest.thrift
@@ -0,0 +1,17 @@
+namespace java thrift.test
+namespace cpp thrift.test
+
+// more tests on double constants (precision and type checks)
+const double DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST = 1
+const double DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST = -100
+const double DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST = 9223372036854775807
+const double DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST = -9223372036854775807
+const double DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST = 3.14159265359
+const double DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST = 1000000.1
+const double DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST = -1000000.1
+const double DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST = 1.7e+308
+const double DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST = 9223372036854775816.43
+const double DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST = -1.7e+308
+const double DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST = -9223372036854775816.43
+
+const list<double> DOUBLE_LIST_TEST = [1,-100,100,9223372036854775807,-9223372036854775807,3.14159265359,1000000.1,-1000000.1,1.7e+308,-1.7e+308,9223372036854775816.43,-9223372036854775816.43]
diff --git a/test/Makefile.am b/test/Makefile.am
index cb3d9aa..7267066 100755
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -134,6 +134,7 @@
 	BrokenConstants.thrift \
 	ConstantsDemo.thrift \
 	DebugProtoTest.thrift \
+	DoubleConstantsTest.thrift \
 	DenseLinkingTest.thrift \
 	DocTest.thrift \
 	EnumTest.thrift \
diff --git a/test/py/Makefile.am b/test/py/Makefile.am
index b3513dd..8296200 100644
--- a/test/py/Makefile.am
+++ b/test/py/Makefile.am
@@ -23,24 +23,31 @@
 thrift_gen =                                    \
         gen-py/ThriftTest/__init__.py           \
         gen-py/DebugProtoTest/__init__.py \
+        gen-py/DoubleConstantsTest/__init__.py \
         gen-py/Recursive/__init__.py \
         gen-py-default/ThriftTest/__init__.py           \
         gen-py-default/DebugProtoTest/__init__.py \
+        gen-py-default/DoubleConstantsTest/__init__.py \
         gen-py-default/Recursive/__init__.py \
         gen-py-slots/ThriftTest/__init__.py           \
         gen-py-slots/DebugProtoTest/__init__.py \
+        gen-py-slots/DoubleConstantsTest/__init__.py \
         gen-py-slots/Recursive/__init__.py \
         gen-py-oldstyle/ThriftTest/__init__.py \
         gen-py-oldstyle/DebugProtoTest/__init__.py \
+        gen-py-oldstyle/DoubleConstantsTest/__init__.py \
         gen-py-oldstyle/Recursive/__init__.py \
         gen-py-no_utf8strings/ThriftTest/__init__.py \
         gen-py-no_utf8strings/DebugProtoTest/__init__.py \
+        gen-py-no_utf8strings/DoubleConstantsTest/__init__.py \
         gen-py-no_utf8strings/Recursive/__init__.py \
         gen-py-dynamic/ThriftTest/__init__.py           \
         gen-py-dynamic/DebugProtoTest/__init__.py \
+        gen-py-dynamic/DoubleConstantsTest/__init__.py \
         gen-py-dynamic/Recursive/__init__.py \
         gen-py-dynamicslots/ThriftTest/__init__.py           \
         gen-py-dynamicslots/DebugProtoTest/__init__.py \
+        gen-py-dynamicslots/DoubleConstantsTest/__init__.py \
         gen-py-dynamicslots/Recursive/__init__.py
 
 
diff --git a/test/py/RunClientServer.py b/test/py/RunClientServer.py
index 7c0f787..b213d1a 100755
--- a/test/py/RunClientServer.py
+++ b/test/py/RunClientServer.py
@@ -38,6 +38,7 @@
 SCRIPTS = [
     'FastbinaryTest.py',
     'TestFrozen.py',
+    'TestRenderedDoubleConstants.py',
     'TSimpleJSONProtocolTest.py',
     'SerializationTest.py',
     'TestEof.py',
diff --git a/test/py/TestRenderedDoubleConstants.py b/test/py/TestRenderedDoubleConstants.py
new file mode 100644
index 0000000..20903d8
--- /dev/null
+++ b/test/py/TestRenderedDoubleConstants.py
@@ -0,0 +1,177 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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
+#
+# 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.
+#
+
+import unittest
+
+from DoubleConstantsTest import constants
+
+#
+# In order to run the test under Windows. We need to create symbolic link
+# name 'thrift' to '../src' folder by using:
+#
+# mklink /D thrift ..\src
+#
+
+
+class TestRenderedDoubleConstants(unittest.TestCase):
+    ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST = \
+        "failed to verify a double constant generated by Thrift (expected = %f, got = %f)"
+    ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_LIST_TEST =\
+        "failed to verify a list item by Thrift (expected = %f, got = %f)"
+    ASSERTION_MESSAGE_FOR_TYPE_CHECKS = "the rendered variable with name %s is not of double type"
+
+    # to make sure the variables inside Thrift files are generated correctly
+    def test_rendered_double_constants(self):
+        EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT = 1.0
+        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT = -100.0
+        EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT = 9223372036854775807.0
+        EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT = -9223372036854775807.0
+        EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS = 3.14159265359
+        EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE = 1000000.1
+        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE = -1000000.1
+        EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE = 1.7e+308
+        EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE = 9223372036854775816.43
+        EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE = -1.7e+308
+        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE = -9223372036854775816.43
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT, constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
+            places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
+                constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
+            places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
+                constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
+            places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
+                constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST,
+            EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS,
+                constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
+            places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST,
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST,
+            EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST,
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST))
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST")
+
+    # to make sure the variables inside Thrift files are generated correctly
+    def test_rendered_double_list(self):
+        EXPECTED_DOUBLE_LIST = [1.0, -100.0, 100.0, 9223372036854775807.0, -9223372036854775807.0, 3.14159265359,
+                                1000000.1, -1000000.1, 1.7e+308, -1.7e+308, 9223372036854775816.43,
+                                -9223372036854775816.43]
+        self.assertEqual(len(constants.DOUBLE_LIST_TEST), len(EXPECTED_DOUBLE_LIST))
+        for i, expectedValue in enumerate(EXPECTED_DOUBLE_LIST):
+            self.assertAlmostEqual(constants.DOUBLE_LIST_TEST[i], expectedValue, places=7)
+
+
+def suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    suite.addTest(loader.loadTestsFromTestCase(TestRenderedDoubleConstants))
+    return suite
+
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/generate.cmake b/test/py/generate.cmake
index 46263c8..4ed14cc 100644
--- a/test/py/generate.cmake
+++ b/test/py/generate.cmake
@@ -21,6 +21,13 @@
 generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic gen-py-dynamic)
 generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic,slots gen-py-dynamicslots)
 
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:dynamic,slots gen-py-dynamicslots)
+
 generate(${MY_PROJECT_DIR}/test/Recursive.thrift py gen-py-default)
 generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:slots gen-py-slots)
 generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:old_style gen-py-oldstyle)