javascript/core: Allow clients to use trailing undefined args/cb
Fixes and tests: https://github.com/vanadium/issues/issues/715
The goal was to still allow us to have the undefined cb while also
having the undefined trailing arg. This CL addresses the accidental
assumption that a trailing undefined was always a cb and tests that
case in test-js-client-server.js
Change-Id: I1cd97539c8e246a4fb88d4f499607b065639be3e
diff --git a/src/rpc/client.js b/src/rpc/client.js
index 7f6fdea..1b524c4 100644
--- a/src/rpc/client.js
+++ b/src/rpc/client.js
@@ -452,7 +452,7 @@
// Callback is the last function argument, pull it out of the args
var lastType = typeof args[args.length - 1];
- if (lastType === 'function' || lastType === 'undefined') {
+ if (lastType === 'function') {
callback = args.pop();
}
@@ -482,7 +482,16 @@
ctx = vtrace.withNewSpan(ctx, '<jsclient>"'+name+'".'+method);
+ // If the last value was undefined, and there is 1 too many args, the
+ // undefined is an undefined cb, not an undefined arg.
+ if (args.length === methodSig.inArgs.length + 1 &&
+ lastType === 'undefined') {
+
+ args.pop();
+ }
+
if (args.length !== methodSig.inArgs.length) {
+
var expectedArgs = methodSig.inArgs.map(function(arg) {
return arg.name;
});
@@ -500,7 +509,7 @@
// The given arguments exclude the ctx and (optional) cb.
var givenArgs = Array.prototype.slice.call(arguments, 1);
- if (typeof givenArgs[givenArgs.length - 1] === 'function') {
+ if (lastType === 'function') {
givenArgs.pop();
}
err = new IncorrectArgCount(
diff --git a/test/integration/test-js-client-server.js b/test/integration/test-js-client-server.js
index d909e9c..7866b17 100644
--- a/test/integration/test-js-client-server.js
+++ b/test/integration/test-js-client-server.js
@@ -353,6 +353,63 @@
});
});
+ test(namePrefix + 'typeService.isTyped(...) - promise', function(t) {
+ setup(options, function(err, ctx, typeService, end) {
+ t.error(err, 'should not error on setup');
+
+ typeService.isTyped(ctx, 'glue').then(function(res) {
+ t.error(err, 'should not error on isTyped(...)');
+ // Use equal instead of notOk to ensure that res is not wrapped.
+ t.equal(res, false, '\'glue\' is an untyped string');
+
+ var VomStr = vdl.registry.lookupOrCreateConstructor(vdl.types.STRING);
+ var typedString = new VomStr('glued');
+ typeService.isTyped(ctx, typedString, function(err, res) {
+ t.error(err, 'should not error on isTyped(...)');
+ // Use equal instead of ok to ensure that res is not wrapped.
+ t.equal(res, true, 'VomStr(\'glued\') is a typed string');
+ end(t);
+ });
+ }).catch(function error(err) {
+ t.error(err, 'should not error');
+ end(t);
+ });
+ });
+ });
+
+ test(namePrefix + 'typeService.isTyped(undefined) - promise', function(t) {
+ setup(options, function(err, ctx, typeService, end) {
+ t.error(err, 'should not error on setup');
+
+ // Check that you can leave an optional (or any) inArg as undefined.
+ // It should not be mistaken for a callback.
+ typeService.isTyped(ctx, undefined).then(function(res) {
+ t.error(err, 'should not error on isTyped(undefined)');
+ t.equal(res, false, 'undefined is treated like JSValue null');
+
+ // Lenient: Having both arg and cb as undefined is fine too.
+ typeService.isTyped(ctx, undefined, undefined).then(function(res) {
+ t.error(err, 'should not error on isTyped(undefined, undefined)');
+ t.equal(res, false, 'undefined is treated like JSValue null');
+
+ // Having any more undefined's is an error (too many args).
+ typeService.isTyped(ctx, undefined, undefined, undefined).then(
+ function(res) {
+
+ t.fail(err, 'should have errored');
+ end(t);
+ }).catch(function(err) {
+ t.ok(err, 'should error');
+ end(t);
+ });
+ });
+ }).catch(function error(err) {
+ t.error(err, 'should not error');
+ end(t);
+ });
+ });
+ });
+
// This test ensures that typed values sent between JS server and client are
// unwrapped when being processed. Further, the client disallows sending the
// wrong type to the server.