THRIFT-4675: Generate Int64 constants for js
diff --git a/lib/js/test/build.xml b/lib/js/test/build.xml
index 04c1360..4795fd2 100755
--- a/lib/js/test/build.xml
+++ b/lib/js/test/build.xml
@@ -28,13 +28,13 @@
   <property name="build" location="build" />
   <property name="jar.file" location="${build}/jstest.jar" />
 
-  <!-- the root directory, where you unpack thrift distibution (e.g. thrift-0.x.x.tar.gz) -->
+  <!-- the root directory, where you unpack thrift distibution (e.g.: thrift-0.x.x.tar.gz) -->
   <property name="thrift.dir" location="../../../" />
   <property name="thrift.java.dir" location="${thrift.dir}/lib/java" />
   <property name="build.tools.dir" location="${thrift.java.dir}/build/tools/"/>
   <property file="${basedir}/build.properties"/>
 
-  <!-- Include the base java properties file -->
+  <!-- Include the base Java properties file -->
   <property file="${thrift.java.dir}/gradle.properties" />
 
   <property name="thrift.compiler" location="${thrift.dir}/compiler/cpp/thrift" />
@@ -187,7 +187,6 @@
     -->
     <jsl:jslint options="evil,forin,browser,bitwise,regexp,newcap,immed" encoding="UTF-8">
       <formatter type="plain" />
-      <fileset dir="${genjs}" includes="**/*.js" />
       <fileset dir="../src" includes="thrift.js" />
 
       <!-- issues with unsafe character -->
diff --git a/lib/js/test/test-deep-constructor.html b/lib/js/test/test-deep-constructor.html
index dfc0da6..462481a 100755
--- a/lib/js/test/test-deep-constructor.html
+++ b/lib/js/test/test-deep-constructor.html
@@ -22,6 +22,7 @@
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Thrift Javascript Bindings: Unit Test</title>
 
+  <script src="build/js/lib/JSONInt64.js" type="text/javascript" charset="utf-8"></script>
   <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
   <script src="gen-js/JsDeepConstructorTest_types.js" type="text/javascript" charset="utf-8"></script>
   <!-- jQuery -->
diff --git a/lib/js/test/test-es6.html b/lib/js/test/test-es6.html
index bf04901..f0b8dd9 100644
--- a/lib/js/test/test-es6.html
+++ b/lib/js/test/test-es6.html
@@ -22,6 +22,9 @@
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Thrift Javascript Bindings: Unit Test</title>
 
+  <script src="build/js/lib/Int64.js" type="text/javascript" charset="utf-8"></script>
+  <script src="build/js/lib/Int64Util.js" type="text/javascript" charset="utf-8"></script>
+  <script src="build/js/lib/JSONInt64.js" type="text/javascript" charset="utf-8"></script>
   <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
   <script src="gen-js-es6/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
   <script src="gen-js-es6/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
diff --git a/lib/js/test/test-int64.html b/lib/js/test/test-int64.html
new file mode 100644
index 0000000..620e6ff
--- /dev/null
+++ b/lib/js/test/test-int64.html
@@ -0,0 +1,55 @@
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!--
+  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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+      <title>Int64 Constants in JS: Unit Test</title>
+
+      <script src="build/js/thrift.js" type="text/javascript" charset="utf-8"></script>
+      <!-- browserified node-int64 -->
+      <script src="build/js/lib/Int64.js" type="text/javascript" charset="utf-8"></script>
+      <!-- int64 constants to check -->
+      <script src="gen-js/Int64Test_types.js" type="text/javascript" charset="utf-8"></script>
+
+      <!-- jQuery -->
+      <script type="text/javascript" src="build/js/lib/jquery.js" charset="utf-8"></script>
+
+      <!-- QUnit Test framework-->
+      <script type="text/javascript" src="build/js/lib/qunit.js" charset="utf-8"></script>
+      <link rel="stylesheet" href="build/js/lib/qunit.css" type="text/css" media="screen" />
+
+      <!-- the Test Suite-->
+      <script type="text/javascript" src="test-int64.js" charset="utf-8"></script>
+    </head>
+<body>
+  <h1 id="qunit-header">Int64 Constants in JS: Unit Test</h1>
+  <h2 id="qunit-banner"></h2>
+  <div id="qunit-testrunner-toolbar"></div>
+  <h2 id="qunit-userAgent"></h2>
+  <ol id="qunit-tests"><li><!-- get valid xhtml strict--></li></ol>
+  <!-- Uncomment this to check the validity. This significantly slows down the test.
+  <p>
+      <a href="http://validator.w3.org/check/referer"><img
+          src="http://www.w3.org/Icons/valid-xhtml10"
+          alt="Valid XHTML 1.0!" height="31" width="88" /></a>
+  </p>
+  -->
+</body>
+</html>
diff --git a/lib/js/test/test-int64.js b/lib/js/test/test-int64.js
new file mode 100644
index 0000000..4df87e1
--- /dev/null
+++ b/lib/js/test/test-int64.js
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+ /* jshint -W100 */
+
+// Work around for old API used by QUnitAdapter of jsTestDriver
+if (typeof QUnit.log == 'function') {
+  // When using real QUnit (fron PhantomJS) log failures to console
+  QUnit.log(function(details) {
+    if (!details.result) {
+      console.log('======== FAIL ========');
+      console.log('TestName: ' + details.name);
+      if (details.message) console.log(details.message);
+      console.log('Expected: ' + details.expected);
+      console.log('Actual  : ' + details.actual);
+      console.log('======================');
+    }
+  });
+}
+
+QUnit.module('Int64');
+
+  QUnit.test('Int64', function(assert) {
+    console.log('Int64 test -- starts');
+    const EXPECTED_SMALL_INT64_AS_NUMBER = 42;
+    const EXPECTED_SMALL_INT64 = new Int64(42);
+    const EXPECTED_MAX_JS_SAFE_INT64 = new Int64(Number.MAX_SAFE_INTEGER);
+    const EXPECTED_MIN_JS_SAFE_INT64 = new Int64(Number.MIN_SAFE_INTEGER);
+    const EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64 = new Int64("0020000000000000"); // hex-encoded
+    const EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64 = new Int64("ffe0000000000000"); // hex-encoded 2's complement
+    const EXPECTED_MAX_SIGNED_INT64 = new Int64("7fffffffffffffff"); // hex-encoded
+    const EXPECTED_MIN_SIGNED_INT64 = new Int64("8000000000000000"); // hex-encoded 2's complement
+    const EXPECTED_INT64_LIST = [
+      EXPECTED_SMALL_INT64,
+      EXPECTED_MAX_JS_SAFE_INT64,
+      EXPECTED_MIN_JS_SAFE_INT64,
+      EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64,
+      EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64,
+      EXPECTED_MAX_SIGNED_INT64,
+      EXPECTED_MIN_SIGNED_INT64
+    ];
+
+    assert.ok(EXPECTED_SMALL_INT64.equals(Int64Test.SMALL_INT64));
+    assert.ok(EXPECTED_MAX_JS_SAFE_INT64.equals(Int64Test.MAX_JS_SAFE_INT64));
+    assert.ok(EXPECTED_MIN_JS_SAFE_INT64.equals(Int64Test.MIN_JS_SAFE_INT64));
+    assert.ok(
+      EXPECTED_MAX_JS_SAFE_PLUS_ONE_INT64.equals(
+        Int64Test.MAX_JS_SAFE_PLUS_ONE_INT64
+      )
+    );
+    assert.ok(
+      EXPECTED_MIN_JS_SAFE_MINUS_ONE_INT64.equals(
+        Int64Test.MIN_JS_SAFE_MINUS_ONE_INT64
+      )
+    );
+    assert.ok(EXPECTED_MAX_SIGNED_INT64.equals(Int64Test.MAX_SIGNED_INT64));
+    assert.ok(EXPECTED_MIN_SIGNED_INT64.equals(Int64Test.MIN_SIGNED_INT64));
+    assert.equal(
+      EXPECTED_SMALL_INT64_AS_NUMBER,
+      Int64Test.SMALL_INT64.toNumber()
+    );
+    assert.equal(
+      Number.MAX_SAFE_INTEGER,
+      Int64Test.MAX_JS_SAFE_INT64.toNumber()
+    );
+    assert.equal(
+      Number.MIN_SAFE_INTEGER,
+      Int64Test.MIN_JS_SAFE_INT64.toNumber()
+    );
+
+    for (let i = 0; i < EXPECTED_INT64_LIST.length; ++i) {
+      assert.ok(EXPECTED_INT64_LIST[i].equals(Int64Test.INT64_LIST[i]));
+    }
+    console.log('Int64 test -- ends');
+  });
+
diff --git a/lib/js/test/test-nojq.html b/lib/js/test/test-nojq.html
index 408424e..37b3eb8 100644
--- a/lib/js/test/test-nojq.html
+++ b/lib/js/test/test-nojq.html
@@ -22,6 +22,9 @@
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Thrift Javascript Bindings: Unit Test</title>
 
+  <script src="build/js/lib/Int64.js" type="text/javascript" charset="utf-8"></script>
+  <script src="build/js/lib/Int64Util.js" type="text/javascript" charset="utf-8"></script>
+  <script src="build/js/lib/JSONInt64.js" type="text/javascript" charset="utf-8"></script>
   <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
   <script src="gen-js/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
   <script src="gen-js/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
diff --git a/lib/js/test/test.html b/lib/js/test/test.html
index 8b67014..85c8395 100755
--- a/lib/js/test/test.html
+++ b/lib/js/test/test.html
@@ -22,6 +22,9 @@
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Thrift Javascript Bindings: Unit Test</title>
 
+  <script src="build/js/lib/Int64.js" type="text/javascript" charset="utf-8"></script>
+  <script src="build/js/lib/Int64Util.js" type="text/javascript" charset="utf-8"></script>
+  <script src="build/js/lib/JSONInt64.js" type="text/javascript" charset="utf-8"></script>
   <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
   <script src="gen-js-jquery/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
   <script src="gen-js-jquery/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
diff --git a/lib/js/test/test.js b/lib/js/test/test.js
index a86a509..35ed6ff 100755
--- a/lib/js/test/test.js
+++ b/lib/js/test/test.js
@@ -51,6 +51,9 @@
 const protocol = new Thrift.Protocol(transport);
 const client = new ThriftTest.ThriftTestClient(protocol);
 
+const int64_2_pow_60 = new Int64('1000000000000000');
+const int64_minus_2_pow_60 = new Int64('f000000000000000');
+
 // Work around for old API used by QUnitAdapter of jsTestDriver
 if (typeof QUnit.log == 'function') {
   // When using real QUnit (fron PhantomJS) log failures to console
@@ -132,9 +135,12 @@
   });
   QUnit.test('I64', function(assert) {
     assert.equal(client.testI64(0), 0);
-    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
-    assert.equal(client.testI64(Math.pow(2, 52)), Math.pow(2, 52));
-    assert.equal(client.testI64(-Math.pow(2, 52)), -Math.pow(2, 52));
+
+    let int64_2_pow_60_result = client.testI64(int64_2_pow_60);
+    assert.ok(int64_2_pow_60.equals(int64_2_pow_60_result));
+
+    let int64_minus_2_pow_60_result = client.testI64(int64_minus_2_pow_60);
+    assert.ok(int64_minus_2_pow_60.equals(int64_minus_2_pow_60_result));
   });
 
 
@@ -145,15 +151,14 @@
     structTestInput.string_thing = 'worked';
     structTestInput.byte_thing = 0x01;
     structTestInput.i32_thing = Math.pow(2, 30);
-    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
-    structTestInput.i64_thing = Math.pow(2, 52);
+    structTestInput.i64_thing = int64_2_pow_60;
 
     const structTestOutput = client.testStruct(structTestInput);
 
     assert.equal(structTestOutput.string_thing, structTestInput.string_thing);
     assert.equal(structTestOutput.byte_thing, structTestInput.byte_thing);
     assert.equal(structTestOutput.i32_thing, structTestInput.i32_thing);
-    assert.equal(structTestOutput.i64_thing, structTestInput.i64_thing);
+    assert.ok(structTestOutput.i64_thing.equals(structTestInput.i64_thing));
 
     assert.equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput));
   });
@@ -163,8 +168,7 @@
     xtrTestInput.string_thing = 'worked';
     xtrTestInput.byte_thing = 0x01;
     xtrTestInput.i32_thing = Math.pow(2, 30);
-    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
-    xtrTestInput.i64_thing = Math.pow(2, 52);
+    xtrTestInput.i64_thing = int64_2_pow_60;
 
     const nestTestInput = new ThriftTest.Xtruct2();
     nestTestInput.byte_thing = 0x02;
@@ -177,7 +181,7 @@
     assert.equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing);
     assert.equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing);
     assert.equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing);
-    assert.equal(nestTestOutput.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing);
+    assert.ok(nestTestOutput.struct_thing.i64_thing.equals(nestTestInput.struct_thing.i64_thing));
     assert.equal(nestTestOutput.i32_thing, nestTestInput.i32_thing);
 
     assert.equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput));
@@ -252,7 +256,7 @@
     structTestInput.string_thing = 'worked';
     structTestInput.byte_thing = 0x01;
     structTestInput.i32_thing = Math.pow(2, 30);
-    structTestInput.i64_thing = Math.pow(2, 52);
+    structTestInput.i64_thing = int64_2_pow_60;
 
     const structTestOutput = modifiedClient.testStruct(structTestInput);
 
@@ -260,7 +264,7 @@
     assert.equal(structTestOutput.string_thing, structTestInput.string_thing);
     assert.equal(structTestOutput.changed, null);
     assert.equal(structTestOutput.i32_thing, structTestInput.i32_thing);
-    assert.equal(structTestOutput.i64_thing, structTestInput.i64_thing);
+    assert.ok(structTestOutput.i64_thing.equals(structTestInput.i64_thing));
   });
 
 
@@ -332,13 +336,13 @@
       'string_thing': 'Goodbye4',
       'byte_thing': 4,
       'i32_thing': 4,
-      'i64_thing': 4
+      'i64_thing': new Int64(4)
     },
     {
       'string_thing': 'Hello2',
       'byte_thing': 2,
       'i32_thing': 2,
-      'i64_thing': 2
+      'i64_thing': new Int64(2)
     }]
   };
   QUnit.test('testInsanity', function(assert) {
@@ -401,15 +405,13 @@
     assert.expect(2);
 
     const done = assert.async(2);
-    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
-    client.testI64(Math.pow(2, 52), function(result) {
-      assert.equal(result, Math.pow(2, 52));
+    client.testI64(int64_2_pow_60, function(result) {
+      assert.ok(int64_2_pow_60.equals(result));
       done();
     });
 
-    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
-    client.testI64(Math.pow(-2, 52), function(result) {
-      assert.equal(result, Math.pow(-2, 52));
+    client.testI64(int64_minus_2_pow_60, function(result) {
+      assert.ok(int64_minus_2_pow_60.equals(result));
       done();
     });
   });
diff --git a/lib/js/test/test_handler.js b/lib/js/test/test_handler.js
index af5f7bd..8ba296b 100644
--- a/lib/js/test/test_handler.js
+++ b/lib/js/test/test_handler.js
@@ -24,6 +24,7 @@
 const genFolder = es6Mode ? 'gen-nodejs-es6' : 'gen-nodejs';
 const ttypes = require(`./${genFolder}/ThriftTest_types`);
 const TException = require('../../nodejs/lib/thrift').TException;
+const Int64 = require('node-int64');
 
 exports.ThriftTestHandler = {
   testVoid: function(result) {
@@ -122,13 +123,13 @@
     hello.string_thing = 'Hello2';
     hello.byte_thing = 2;
     hello.i32_thing = 2;
-    hello.i64_thing = 2;
+    hello.i64_thing = new Int64(2);
 
     const goodbye = new ttypes.Xtruct();
     goodbye.string_thing = 'Goodbye4';
     goodbye.byte_thing = 4;
     goodbye.i32_thing = 4;
-    goodbye.i64_thing = 4;
+    goodbye.i64_thing = new Int64(4);
 
     const crazy = new ttypes.Insanity();
     crazy.userMap = [];
diff --git a/lib/js/test/testws.html b/lib/js/test/testws.html
index 184500f..5ff9f22 100644
--- a/lib/js/test/testws.html
+++ b/lib/js/test/testws.html
@@ -22,6 +22,9 @@
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Thrift Javascript Bindings: Unit Test</title>
 
+  <script src="build/js/lib/Int64.js" type="text/javascript" charset="utf-8"></script>
+  <script src="build/js/lib/Int64Util.js" type="text/javascript" charset="utf-8"></script>
+  <script src="build/js/lib/JSONInt64.js" type="text/javascript" charset="utf-8"></script>
   <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
   <script src="gen-js/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
   <script src="gen-js/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>