js-only: Separate error from out args

Change-Id: I1446168173e3fa4394356cc34527750f3e8f886e
MultiPart: 1/4
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index a472e68..65b9d0a 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -67,7 +67,7 @@
 
 	errArgEncoding = verror.Register(pkgPath+".argEncoding", verror.NoRetry, "failed to encode arg #{3}{:4:}")
 
-	errMismatchedResults = verror.Register(pkgPath+".mismatchedResults", verror.NoRetry, "expected {3} results, but got {4}")
+	errMismatchedResults = verror.Register(pkgPath+".mismatchedResults", verror.NoRetry, "got {3} results, but want {4}")
 
 	errResultDecoding = verror.Register(pkgPath+".resultDecoding", verror.NoRetry, "failed to decode result #{3}{:4}")
 
diff --git a/runtimes/google/testing/mocks/ipc/simple_client.go b/runtimes/google/testing/mocks/ipc/simple_client.go
index 23a6b89..d90ccd7 100644
--- a/runtimes/google/testing/mocks/ipc/simple_client.go
+++ b/runtimes/google/testing/mocks/ipc/simple_client.go
@@ -3,13 +3,14 @@
 import (
 	"errors"
 	"fmt"
-	"reflect"
 	"sync"
 
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/security"
+	"v.io/core/veyron2/vdl/valconv"
 	"v.io/core/veyron2/vlog"
+	"v.io/core/veyron2/vom2"
 )
 
 // NewSimpleClient creates a new mocked ipc client where the given map of method name
@@ -51,8 +52,21 @@
 		return nil, errors.New(fmt.Sprintf("method %s not found", method))
 	}
 
+	// Copy the results so that they can be modified without effecting the original.
+	// This must be done via vom encode and decode rather than a direct deep copy because (among other reasons)
+	// reflect-based deep copy on vdl.Type objects will fail because of their private fields. This is not a problem with vom
+	// as it manually creates the type objects. It is also more realistic to use the same mechanism as the ultimate calls.
+	vomBytes, err := vom2.Encode(results)
+	if err != nil {
+		panic(fmt.Sprintf("Error copying value with vom (failed on encode): %v", err))
+	}
+	var copiedResults []interface{}
+	if err := vom2.Decode(vomBytes, &copiedResults); err != nil {
+		panic(fmt.Sprintf("Error copying value with vom (failed on decode): %v", err))
+	}
+
 	clientCall := mockCall{
-		results: results,
+		results: copiedResults,
 	}
 
 	c.Lock()
@@ -92,10 +106,11 @@
 	}
 	for ax, res := range resultptrs {
 		if mc.results[ax] != nil {
-			reflect.ValueOf(res).Elem().Set(reflect.ValueOf(mc.results[ax]))
+			if err := valconv.Convert(res, mc.results[ax]); err != nil {
+				panic(fmt.Sprintf("Error converting out argument %#v: %v", mc.results[ax], err))
+			}
 		}
 	}
-
 	return nil
 }
 
diff --git a/runtimes/google/testing/mocks/ipc/simple_client_test.go b/runtimes/google/testing/mocks/ipc/simple_client_test.go
index 0cf23e6..a4bd4f0 100644
--- a/runtimes/google/testing/mocks/ipc/simple_client_test.go
+++ b/runtimes/google/testing/mocks/ipc/simple_client_test.go
@@ -35,7 +35,7 @@
 		return
 	}
 	var resultOne string
-	var resultTwo int
+	var resultTwo int64
 	method1Call.Finish(&resultOne, &resultTwo)
 	if resultOne != "one" {
 		t.Errorf(`FinishCall: first result was "%v", want "one"`, resultOne)
@@ -73,21 +73,21 @@
 }
 
 type sampleStruct struct {
-	name string
+	Name string
 }
 
 func TestStructResult(t *testing.T) {
 	client := NewSimpleClient(map[string][]interface{}{
 		"foo": []interface{}{
-			sampleStruct{name: "bar"},
+			sampleStruct{Name: "bar"},
 		},
 	})
 	ctx := testContext()
 	call, _ := client.StartCall(ctx, "name/obj", "foo", []interface{}{})
 	var result sampleStruct
 	call.Finish(&result)
-	if result.name != "bar" {
-		t.Errorf(`FinishCall: second result was "%v", want "bar"`, result.name)
+	if result.Name != "bar" {
+		t.Errorf(`FinishCall: second result was "%v", want "bar"`, result.Name)
 		return
 	}
 }