diff options
-rw-r--r-- | compiler/cpp/src/generate/t_js_generator.cc | 61 | ||||
-rw-r--r-- | lib/js/Gruntfile.js | 21 | ||||
-rw-r--r-- | lib/js/src/thrift.js | 68 | ||||
-rw-r--r-- | lib/js/test/deep-constructor.test.js | 195 | ||||
-rwxr-xr-x | lib/js/test/test-deep-constructor.html | 49 | ||||
-rw-r--r-- | lib/nodejs/lib/thrift/json_protocol.js | 10 | ||||
-rw-r--r-- | lib/nodejs/lib/thrift/thrift.js | 67 | ||||
-rw-r--r-- | lib/nodejs/test/deep-constructor.test.js | 233 | ||||
-rw-r--r-- | lib/nodejs/test/test-cases.js | 17 | ||||
-rwxr-xr-x | lib/nodejs/test/testAll.sh | 2 | ||||
-rw-r--r-- | lib/nodejs/test/test_driver.js | 11 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | test/JsDeepConstructorTest.thrift | 12 |
13 files changed, 737 insertions, 10 deletions
diff --git a/compiler/cpp/src/generate/t_js_generator.cc b/compiler/cpp/src/generate/t_js_generator.cc index 970a179f9..2c90e4ced 100644 --- a/compiler/cpp/src/generate/t_js_generator.cc +++ b/compiler/cpp/src/generate/t_js_generator.cc @@ -41,6 +41,7 @@ static const string endl = "\n"; // avoid ostream << std::endl flushes #include "t_oop_generator.h" + /** * JS code generator. */ @@ -181,6 +182,8 @@ public: + "//\n"; } + t_type* get_contained_type(t_type* t); + std::vector<std::string> js_namespace_pieces(t_program* p) { std::string ns = p->get_namespace("js"); @@ -601,6 +604,22 @@ void t_js_generator::generate_js_struct(t_struct* tstruct, bool is_exception) { } /** + * Return type of contained elements for a container type. For maps + * this is type of value (keys are always strings in js) + */ +t_type* t_js_generator::get_contained_type(t_type* t) { + t_type* etype; + if (t->is_list()) { + etype = ((t_list*)t)->get_elem_type(); + } else if (t->is_set()) { + etype = ((t_set*)t)->get_elem_type(); + } else { + etype = ((t_map*)t)->get_val_type(); + } + return etype; +} + +/** * Generates a struct definition for a thrift data type. This is nothing in JS * where the objects are all just associative arrays (unless of course we * decide to start using objects for them...) @@ -685,9 +704,47 @@ void t_js_generator::generate_js_struct_definition(ofstream& out, } for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { + t_type* t = get_true_type((*m_iter)->get_type()); out << indent() << indent() << "if (args." << (*m_iter)->get_name() << " !== undefined) {" - << endl << indent() << indent() << indent() << "this." << (*m_iter)->get_name() - << " = args." << (*m_iter)->get_name() << ";" << endl; + << endl << indent() << indent() << indent() << "this." << (*m_iter)->get_name(); + + if (t->is_struct()) { + out << (" = new " + js_type_namespace(t->get_program()) + t->get_name() + + "(args."+(*m_iter)->get_name() +");"); + out << endl; + } else if (t->is_container()) { + t_type* etype = get_contained_type(t); + string copyFunc = t->is_map() ? "Thrift.copyMap" : "Thrift.copyList"; + string type_list = ""; + + while (etype->is_container()) { + if (type_list.length() > 0) { + type_list += ", "; + } + type_list += etype->is_map() ? "Thrift.copyMap" : "Thrift.copyList"; + etype = get_contained_type(etype); + } + + if (etype->is_struct()) { + if (type_list.length() > 0) { + type_list += ", "; + } + type_list += js_type_namespace(etype->get_program()) + etype->get_name(); + } + else { + if (type_list.length() > 0) { + type_list += ", "; + } + type_list += "null"; + } + + out << (" = " + copyFunc + "(args." + (*m_iter)->get_name() + + ", [" + type_list + "]);"); + out << endl; + } else { + out << " = args." << (*m_iter)->get_name() << ";" << endl; + } + if (!(*m_iter)->get_req()) { out << indent() << indent() << "} else {" << endl << indent() << indent() << indent() << "throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, " diff --git a/lib/js/Gruntfile.js b/lib/js/Gruntfile.js index 3298d5cf2..32c88346b 100644 --- a/lib/js/Gruntfile.js +++ b/lib/js/Gruntfile.js @@ -35,7 +35,7 @@ module.exports = function(grunt) { 'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>'] } } - }, + }, shell: { InstallThriftJS: { command: 'mkdir test/build; mkdir test/build/js; cp src/thrift.js test/build/js/thrift.js' @@ -48,6 +48,9 @@ module.exports = function(grunt) { }, ThriftGenJQ: { command: 'thrift -gen js:jquery -gen js:node -o test ../../test/ThriftTest.thrift' + }, + ThriftGenDeepConstructor: { + command: 'thrift -gen js -o test ../../test/JsDeepConstructorTest.thrift' } }, external_daemon: { @@ -123,6 +126,13 @@ module.exports = function(grunt) { 'https://localhost:8089/testws.html' ] } + }, + ThriftDeepConstructor: { + options: { + urls: [ + 'http://localhost:8088/test-deep-constructor.html' + ] + } } }, jshint: { @@ -147,13 +157,14 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-external-daemon'); grunt.loadNpmTasks('grunt-shell'); - grunt.registerTask('test', ['jshint', 'shell:InstallThriftJS', 'shell:InstallThriftNodeJSDep', 'shell:ThriftGen', - 'external_daemon:ThriftTestServer', 'external_daemon:ThriftTestServer_TLS', + grunt.registerTask('test', ['jshint', 'shell:InstallThriftJS', 'shell:InstallThriftNodeJSDep', 'shell:ThriftGen', + 'external_daemon:ThriftTestServer', 'external_daemon:ThriftTestServer_TLS', + 'shell:ThriftGenDeepConstructor', 'qunit:ThriftDeepConstructor', 'qunit:ThriftJS', 'qunit:ThriftJS_TLS', 'shell:ThriftGenJQ', 'qunit:ThriftJSJQ', 'qunit:ThriftJSJQ_TLS' ]); - grunt.registerTask('default', ['jshint', 'shell:InstallThriftJS', 'shell:InstallThriftNodeJSDep', 'shell:ThriftGen', - 'external_daemon:ThriftTestServer', 'external_daemon:ThriftTestServer_TLS', + grunt.registerTask('default', ['jshint', 'shell:InstallThriftJS', 'shell:InstallThriftNodeJSDep', 'shell:ThriftGen', + 'external_daemon:ThriftTestServer', 'external_daemon:ThriftTestServer_TLS', 'qunit:ThriftJS', 'qunit:ThriftJS_TLS', 'shell:ThriftGenJQ', 'qunit:ThriftJSJQ', 'qunit:ThriftJSJQ_TLS', 'concat', 'uglify', 'jsdoc' diff --git a/lib/js/src/thrift.js b/lib/js/src/thrift.js index af45d9c47..9bd1198ae 100644 --- a/lib/js/src/thrift.js +++ b/lib/js/src/thrift.js @@ -1203,7 +1203,7 @@ Thrift.Protocol.prototype = { r.size = list.shift(); this.rpos.push(this.rstack.length); - this.rstack.push(list); + this.rstack.push(list.shift()); return r; }, @@ -1439,3 +1439,69 @@ Thrift.Multiplexer.prototype.createClient = function (serviceName, SCl, transpor +var copyList, copyMap; + +copyList = function(lst, types) { + + if (!lst) {return lst; } + + var type; + + if (types.shift === undefined) { + type = types; + } + else { + type = types[0]; + } + var Type = type; + + var len = lst.length, result = [], i, val; + for (i = 0; i < len; i++) { + val = lst[i]; + if (type === null) { + result.push(val); + } + else if (type === copyMap || type === copyList) { + result.push(type(val, types.slice(1))); + } + else { + result.push(new Type(val)); + } + } + return result; +}; + +copyMap = function(obj, types){ + + if (!obj) {return obj; } + + var type; + + if (types.shift === undefined) { + type = types; + } + else { + type = types[0]; + } + var Type = type; + + var result = {}, val; + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) { + val = obj[prop]; + if (type === null) { + result[prop] = val; + } + else if (type === copyMap || type === copyList) { + result[prop] = type(val, types.slice(1)); + } + else { + result[prop] = new Type(val); + } + } + } + return result; +}; + +Thrift.copyMap = copyMap; +Thrift.copyList = copyList; diff --git a/lib/js/test/deep-constructor.test.js b/lib/js/test/deep-constructor.test.js new file mode 100644 index 000000000..9a1980943 --- /dev/null +++ b/lib/js/test/deep-constructor.test.js @@ -0,0 +1,195 @@ +function serialize(data) { + var transport = new Thrift.Transport("/service"); + var protocol = new Thrift.Protocol(transport); + protocol.writeMessageBegin("", 0, 0); + data.write(protocol); + protocol.writeMessageEnd(); + return transport.send_buf; +} + +function deserialize(serialized, type) { + var transport = new Thrift.Transport("/service"); + transport.setRecvBuffer(serialized); + var protocol = new Thrift.Protocol(transport); + protocol.readMessageBegin(); + var data = new type(); + data.read(protocol); + protocol.readMessageEnd(); + return data; +} + + +function createThriftObj() { + + return new Complex({ + + struct_field: new Simple({value: 'a'}), + + struct_list_field: [ + new Simple({value: 'b'}), + new Simple({value: 'c'}), + ], + + struct_set_field: [ + new Simple({value: 'd'}), + new Simple({value: 'e'}), + ], + + struct_map_field: { + A: new Simple({value: 'f'}), + B: new Simple({value: 'g'}) + }, + + struct_nested_containers_field: [ + [ + { + C: [ + new Simple({value: 'h'}), + new Simple({value: 'i'}) + ] + } + ] + ], + + + struct_nested_containers_field2: { + D: [ + { + DA: new Simple({value: 'j'}) + }, + { + DB: new Simple({value: 'k'}) + } + ] + } + } + ); +} + + +function createJsObj() { + + return { + + struct_field: {value: 'a'}, + + struct_list_field: [ + {value: 'b'}, + {value: 'c'}, + ], + + struct_set_field: [ + {value: 'd'}, + {value: 'e'}, + ], + + struct_map_field: { + A: {value: 'f'}, + B: {value: 'g'} + }, + + struct_nested_containers_field: [ + [ + { + C: [ + {value: 'h'}, + {value: 'i'} + ] + } + ] + ], + + struct_nested_containers_field2: { + D: [ + { + DA: {value: 'j'} + }, + { + DB: {value: 'k'} + } + ] + } + }; +} + + +function assertValues(obj, assert) { + assert.equal(obj.struct_field.value, 'a'); + assert.equal(obj.struct_list_field[0].value, 'b'); + assert.equal(obj.struct_list_field[1].value, 'c'); + assert.equal(obj.struct_set_field[0].value, 'd'); + assert.equal(obj.struct_set_field[1].value, 'e'); + assert.equal(obj.struct_map_field.A.value, 'f'); + assert.equal(obj.struct_map_field.B.value, 'g'); + assert.equal(obj.struct_nested_containers_field[0][0].C[0].value, 'h'); + assert.equal(obj.struct_nested_containers_field[0][0].C[1].value, 'i'); + assert.equal(obj.struct_nested_containers_field2.D[0].DA.value, 'j'); + assert.equal(obj.struct_nested_containers_field2.D[1].DB.value, 'k'); +} + +var cases = { + + "Serialize/deserialize simple struct should return equal object": function(assert){ + var tObj = new Simple({value: 'a'}); + var received = deserialize(serialize(tObj), Simple); + assert.ok(tObj !== received); + assert.deepEqual(received, tObj); + }, + + + "Serialize/deserialize should return equal object": function(assert){ + var tObj = createThriftObj(); + var received = deserialize(serialize(tObj), Complex); + assert.ok(tObj !== received); + assert.deepEqual(received, tObj); + }, + + "Nested structs and containers initialized from plain js objects should serialize same as if initialized from thrift objects": function(assert) { + var tObj1 = createThriftObj(); + var tObj2 = new Complex(createJsObj()); + assertValues(tObj2, assert); + assert.equal(serialize(tObj2), serialize(tObj1)); + }, + + "Modifications to args object should not affect constructed Thrift object": function (assert) { + + var args = createJsObj(); + assertValues(args, assert); + + var tObj = new Complex(args); + assertValues(tObj, assert); + + args.struct_field.value = 'ZZZ'; + args.struct_list_field[0].value = 'ZZZ'; + args.struct_list_field[1].value = 'ZZZ'; + args.struct_set_field[0].value = 'ZZZ'; + args.struct_set_field[1].value = 'ZZZ'; + args.struct_map_field.A.value = 'ZZZ'; + args.struct_map_field.B.value = 'ZZZ'; + args.struct_nested_containers_field[0][0].C[0] = 'ZZZ'; + args.struct_nested_containers_field[0][0].C[1] = 'ZZZ'; + args.struct_nested_containers_field2.D[0].DA = 'ZZZ'; + args.struct_nested_containers_field2.D[0].DB = 'ZZZ'; + + assertValues(tObj, assert); + }, + + "nulls are ok": function(assert) { + var tObj = new Complex({ + struct_field: null, + struct_list_field: null, + struct_set_field: null, + struct_map_field: null, + struct_nested_containers_field: null, + struct_nested_containers_field2: null + }); + var received = deserialize(serialize(tObj), Complex); + assert.ok(tObj !== received); + assert.deepEqual(tObj, received); + } + +}; + +Object.keys(cases).forEach(function(caseName) { + test(caseName, cases[caseName]); +}); diff --git a/lib/js/test/test-deep-constructor.html b/lib/js/test/test-deep-constructor.html new file mode 100755 index 000000000..5835dc84b --- /dev/null +++ b/lib/js/test/test-deep-constructor.html @@ -0,0 +1,49 @@ +<!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>Thrift Javascript Bindings: Unit Test</title> + + <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 --> + <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.js" charset="utf-8"></script> + + <!-- QUnit Test framework--> + <script type="text/javascript" src="http://code.jquery.com/qunit/qunit-1.14.0.js" charset="utf-8"></script> + <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.14.0.css" type="text/css" media="screen" /> + + <!-- the Test Suite--> + <script type="text/javascript" src="deep-constructor.test.js" charset="utf-8"></script> +</head> +<body> + <h1 id="qunit-header">Thrift Javascript Bindings: Deep Constructor Test (<a href="https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob;f=test/JsDeepConstructorTest.thrift;hb=HEAD">JsDeepConstructorTest.thrift</a>)</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> + <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/nodejs/lib/thrift/json_protocol.js b/lib/nodejs/lib/thrift/json_protocol.js index 77339f7f1..e98650c50 100644 --- a/lib/nodejs/lib/thrift/json_protocol.js +++ b/lib/nodejs/lib/thrift/json_protocol.js @@ -546,9 +546,15 @@ TJSONProtocol.prototype.readFieldEnd = function() { */ TJSONProtocol.prototype.readMapBegin = function() { var map = this.rstack.pop(); + var first = map.shift(); + if (first instanceof Array) { + this.rstack.push(map); + map = first; + first = map.shift(); + } var r = {}; - r.ktype = TJSONProtocol.RType[map.shift()]; + r.ktype = TJSONProtocol.RType[first]; r.vtype = TJSONProtocol.RType[map.shift()]; r.size = map.shift(); @@ -582,7 +588,7 @@ TJSONProtocol.prototype.readListBegin = function() { r.size = list.shift(); this.rpos.push(this.rstack.length); - this.rstack.push(list); + this.rstack.push(list.shift()); return r; }; diff --git a/lib/nodejs/lib/thrift/thrift.js b/lib/nodejs/lib/thrift/thrift.js index 89c789d9f..e6edf9efe 100644 --- a/lib/nodejs/lib/thrift/thrift.js +++ b/lib/nodejs/lib/thrift/thrift.js @@ -151,3 +151,70 @@ exports.objectLength = function(obj) { exports.inherits = function(constructor, superConstructor) { util.inherits(constructor, superConstructor); }; + +var copyList, copyMap; + +copyList = function(lst, types) { + + if (!lst) {return lst; } + + var type; + + if (types.shift === undefined) { + type = types; + } + else { + type = types[0]; + } + var Type = type; + + var len = lst.length, result = [], i, val; + for (i = 0; i < len; i++) { + val = lst[i]; + if (type === null) { + result.push(val); + } + else if (type === copyMap || type === copyList) { + result.push(type(val, types.slice(1))); + } + else { + result.push(new Type(val)); + } + } + return result; +}; + +copyMap = function(obj, types){ + + if (!obj) {return obj; } + + var type; + + if (types.shift === undefined) { + type = types; + } + else { + type = types[0]; + } + var Type = type; + + var result = {}, val; + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) { + val = obj[prop]; + if (type === null) { + result[prop] = val; + } + else if (type === copyMap || type === copyList) { + result[prop] = type(val, types.slice(1)); + } + else { + result[prop] = new Type(val); + } + } + } + return result; +}; + +module.exports.copyMap = copyMap; +module.exports.copyList = copyList; diff --git a/lib/nodejs/test/deep-constructor.test.js b/lib/nodejs/test/deep-constructor.test.js new file mode 100644 index 000000000..41e7dd0b6 --- /dev/null +++ b/lib/nodejs/test/deep-constructor.test.js @@ -0,0 +1,233 @@ +var ttypes = require('./gen-nodejs/JsDeepConstructorTest_types'); +var thrift = require('thrift'); +var test = require('tape'); +var bufferEquals = require('buffer-equals'); + +function serializeBinary(data) { + var buff; + var transport = new thrift.TBufferedTransport(null, function(msg){ + buff = msg; + }); + var prot = new thrift.TBinaryProtocol(transport); + data.write(prot); + prot.flush(); + return buff; + +} + + +function deserializeBinary(serialized, type) { + var t = new thrift.TFramedTransport(serialized); + var p = new thrift.TBinaryProtocol(t); + var data = new type(); + data.read(p); + return data; +} + + +function serializeJSON(data) { + var buff; + var transport = new thrift.TBufferedTransport(null, function(msg){ + buff = msg; + }); + var protocol = new thrift.TJSONProtocol(transport); + protocol.writeMessageBegin("", 0, 0); + data.write(protocol); + protocol.writeMessageEnd(); + protocol.flush(); + return buff; +} + + +function deserializeJSON(serialized, type) { + var transport = new thrift.TFramedTransport(serialized); + var protocol = new thrift.TJSONProtocol(transport); + protocol.readMessageBegin(); + var data = new type(); + data.read(protocol); + protocol.readMessageEnd(); + return data; +} + + +function createThriftObj() { + + return new ttypes.Complex({ + + struct_field: new ttypes.Simple({value: 'a'}), + + struct_list_field: [ + new ttypes.Simple({value: 'b'}), + new ttypes.Simple({value: 'c'}), + ], + + struct_set_field: [ + new ttypes.Simple({value: 'd'}), + new ttypes.Simple({value: 'e'}), + ], + + struct_map_field: { + A: new ttypes.Simple({value: 'f'}), + B: new ttypes.Simple({value: 'g'}) + }, + + struct_nested_containers_field: [ + [ + { + C: [ + new ttypes.Simple({value: 'h'}), + new ttypes.Simple({value: 'i'}) + ] + } + ] + ], + + struct_nested_containers_field2: { + D: [ + { + DA: new ttypes.Simple({value: 'j'}) + }, + { + DB: new ttypes.Simple({value: 'k'}) + } + ] + } + } + ); +} + + +function createJsObj() { + + return { + + struct_field: {value: 'a'}, + + struct_list_field: [ + {value: 'b'}, + {value: 'c'}, + ], + + struct_set_field: [ + {value: 'd'}, + {value: 'e'}, + ], + + struct_map_field: { + A: {value: 'f'}, + B: {value: 'g'} + }, + + struct_nested_containers_field: [ + [ + { + C: [ + {value: 'h'}, + {value: 'i'} + ] + } + ] + ], + + struct_nested_containers_field2: { + D: [ + { + DA: {value: 'j'} + }, + { + DB: {value: 'k'} + } + ] + } + }; +} + + +function assertValues(obj, assert) { + assert.equals(obj.struct_field.value, 'a'); + assert.equals(obj.struct_list_field[0].value, 'b'); + assert.equals(obj.struct_list_field[1].value, 'c'); + assert.equals(obj.struct_set_field[0].value, 'd'); + assert.equals(obj.struct_set_field[1].value, 'e'); + assert.equals(obj.struct_map_field.A.value, 'f'); + assert.equals(obj.struct_map_field.B.value, 'g'); + assert.equals(obj.struct_nested_containers_field[0][0].C[0].value, 'h'); + assert.equals(obj.struct_nested_containers_field[0][0].C[1].value, 'i'); + assert.equals(obj.struct_nested_containers_field2.D[0].DA.value, 'j'); + assert.equals(obj.struct_nested_containers_field2.D[1].DB.value, 'k'); +} + +function createTestCases(serialize, deserialize) { + + var cases = { + + "Serialize/deserialize should return equal object": function(assert){ + var tObj = createThriftObj(); + var received = deserialize(serialize(tObj), ttypes.Complex); + assert.ok(tObj !== received, 'not the same object'); + assert.deepEqual(tObj, received); + assert.end(); + }, + + "Nested structs and containers initialized from plain js objects should serialize same as if initialized from thrift objects": function(assert) { + var tObj1 = createThriftObj(); + var tObj2 = new ttypes.Complex(createJsObj()); + assertValues(tObj2, assert); + var s1 = serialize(tObj1); + var s2 = serialize(tObj2); + assert.ok(bufferEquals(s1, s2)); + assert.end(); + }, + + "Modifications to args object should not affect constructed Thrift object": function (assert) { + + var args = createJsObj(); + assertValues(args, assert); + + var tObj = new ttypes.Complex(args); + assertValues(tObj, assert); + + args.struct_field.value = 'ZZZ'; + args.struct_list_field[0].value = 'ZZZ'; + args.struct_list_field[1].value = 'ZZZ'; + args.struct_set_field[0].value = 'ZZZ'; + args.struct_set_field[1].value = 'ZZZ'; + args.struct_map_field.A.value = 'ZZZ'; + args.struct_map_field.B.value = 'ZZZ'; + args.struct_nested_containers_field[0][0].C[0] = 'ZZZ'; + args.struct_nested_containers_field[0][0].C[1] = 'ZZZ'; + args.struct_nested_containers_field2.D[0].DA = 'ZZZ'; + args.struct_nested_containers_field2.D[0].DB = 'ZZZ'; + + assertValues(tObj, assert); + assert.end(); + }, + + "nulls are ok": function(assert) { + var tObj = new ttypes.Complex({ + struct_field: null, + struct_list_field: null, + struct_set_field: null, + struct_map_field: null, + struct_nested_containers_field: null, + struct_nested_containers_field2: null + }); + var received = deserialize(serialize(tObj), ttypes.Complex); + assert.ok(tObj !== received); + assert.deepEqual(tObj, received); + assert.end(); + } + + }; + return cases; +} + + +function run(name, cases){ + Object.keys(cases).forEach(function(caseName) { + test(name + ': ' + caseName, cases[caseName]); + }); +} + +run('binary', createTestCases(serializeBinary, deserializeBinary)); +run('json', createTestCases(serializeJSON, deserializeJSON)); diff --git a/lib/nodejs/test/test-cases.js b/lib/nodejs/test/test-cases.js index c396ca9bd..787229533 100644 --- a/lib/nodejs/test/test-cases.js +++ b/lib/nodejs/test/test-cases.js @@ -107,6 +107,22 @@ var crazy = new ttypes.Insanity({ })] }); +var crazy2 = new ttypes.Insanity({ + "userMap":{ "5":5, "8":8 }, + "xtructs":[{ + "string_thing":"Goodbye4", + "byte_thing":4, + "i32_thing":4, + "i64_thing":4 + }, { + "string_thing":"Hello2", + "byte_thing":2, + "i32_thing":2, + "i64_thing":2 + }] +}); + + var insanity = { "1":{ "2": crazy, "3": crazy }, "2":{ "6":{ "userMap":{}, "xtructs":[] } } @@ -119,4 +135,5 @@ module.exports.deep = deep; module.exports.out = out; module.exports.out2 = out2; module.exports.crazy = crazy; +module.exports.crazy2 = crazy2; module.exports.insanity = insanity; diff --git a/lib/nodejs/test/testAll.sh b/lib/nodejs/test/testAll.sh index fd1142585..38b284ac9 100755 --- a/lib/nodejs/test/testAll.sh +++ b/lib/nodejs/test/testAll.sh @@ -71,10 +71,12 @@ TESTOK=0 #generating thrift code ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node ${DIR}/../../../test/ThriftTest.thrift +${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node ${DIR}/../../../test/JsDeepConstructorTest.thrift #unit tests node ${DIR}/binary.test.js || TESTOK=1 +node ${DIR}/deep-constructor.test.js || TESTOK=1 #integration tests diff --git a/lib/nodejs/test/test_driver.js b/lib/nodejs/test/test_driver.js index 6e472adf4..27ffd63ec 100644 --- a/lib/nodejs/test/test_driver.js +++ b/lib/nodejs/test/test_driver.js @@ -80,6 +80,11 @@ exports.ThriftTestDriver = function(client, callback) { checkRecursively(testCases.insanity, response, 'testInsanity'); }); + client.testInsanity(testCases.crazy2, function(err, response) { + assert.error(err, 'testInsanity2: no callback error'); + checkRecursively(testCases.insanity, response, 'testInsanity2'); + }); + client.testException('TException', function(err, response) { assert.ok(err instanceof TException, 'testException: correct error type'); assert.ok(!response, 'testException: no response'); @@ -161,6 +166,12 @@ exports.ThriftTestDriverPromise = function(client, callback) { }) .fail(fail('testInsanity')); + client.testInsanity(testCases.crazy2) + .then(function(response) { + checkRecursively(testCases.insanity, response, 'testInsanity2'); + }) + .fail(fail('testInsanity2')); + client.testException('TException') .then(function(response) { fail('testException: TException'); diff --git a/package.json b/package.json index 0fbb80eaa..c4688b62f 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "ws": "~0.4.32" }, "devDependencies": { + "buffer-equals": "^1.0.3", "commander": "2.1.x", "connect": "2.7.x", "istanbul": "^0.3.5", diff --git a/test/JsDeepConstructorTest.thrift b/test/JsDeepConstructorTest.thrift new file mode 100644 index 000000000..9150854b2 --- /dev/null +++ b/test/JsDeepConstructorTest.thrift @@ -0,0 +1,12 @@ +struct Simple { + 1: string value +} + +struct Complex { + 1: Simple struct_field + 2: list<Simple> struct_list_field + 3: set<Simple> struct_set_field + 4: map<string,Simple> struct_map_field + 5: list<set<map<string,list<Simple>>>> struct_nested_containers_field + 6: map<string, list<map<string,Simple>> > struct_nested_containers_field2 +} |