v23proxy: Add additional tests for mojom <-> vom transcoder

Also adds support for int8

Change-Id: Ibe8ad6eee2ebce9b0ea68fc09d774c9a2d668325
diff --git a/Makefile b/Makefile
index 0bb5321..540e2b5 100644
--- a/Makefile
+++ b/Makefile
@@ -56,7 +56,7 @@
 build-dart-examples: gen/echo.mojom.dart gen/fortune.mojom.dart
 
 # Go-based unit tests
-test: $(MOJO_SHARED_LIB) gen/go/src/mojom/tests/transcoder_testcases/transcoder_testcases.mojom.go
+test: $(MOJO_SHARED_LIB) gen/go/src/mojom/tests/transcoder_testcases/transcoder_testcases.mojom.go gen-vdl
 	$(call MOGO_TEST,v.io/x/mojo/transcoder/...)
 
 # Note:This file is needed to compile v23proxy.mojom, so we're symlinking it in from $MOJO_SDK.
@@ -131,6 +131,9 @@
 	# See https://github.com/domokit/mojo/issues/386
 	rm -f lib/gen/mojom/$(notdir $@)
 
+gen-vdl:
+	GOPATH=$(PWD)/go VDLPATH=$(PWD)/go vdl generate all
+
 # Run the Mojo shell with map-origin. This is common to Linux and Android since
 # the latter cannot accept a config-file.
 # $1 is for any extra flags, like --enable-multiprocess.
diff --git a/go/src/v.io/x/mojo/transcoder/allocation_size.go b/go/src/v.io/x/mojo/transcoder/allocation_size.go
index e3ca024..0d9d747 100644
--- a/go/src/v.io/x/mojo/transcoder/allocation_size.go
+++ b/go/src/v.io/x/mojo/transcoder/allocation_size.go
@@ -19,7 +19,7 @@
 	switch vt.Kind() {
 	case vdl.Bool:
 		return 1
-	case vdl.Byte:
+	case vdl.Byte, vdl.Int8:
 		return 8
 	case vdl.Uint16, vdl.Int16:
 		return 16
diff --git a/go/src/v.io/x/mojo/transcoder/mojom_to_vdl.go b/go/src/v.io/x/mojo/transcoder/mojom_to_vdl.go
index fe3eaa5..b0ab52f 100644
--- a/go/src/v.io/x/mojo/transcoder/mojom_to_vdl.go
+++ b/go/src/v.io/x/mojo/transcoder/mojom_to_vdl.go
@@ -27,7 +27,7 @@
 }
 
 type mojomToVdlTranscoder struct {
-	modec *bindings.Decoder
+	modec     *bindings.Decoder
 	typeStack []*vdl.Type
 }
 
@@ -39,6 +39,12 @@
 			return err
 		}
 		return target.FromBool(value, vt)
+	case vdl.Int8:
+		value, err := mtv.modec.ReadInt8()
+		if err != nil {
+			return err
+		}
+		return target.FromInt(int64(value), vt)
 	case vdl.Int16:
 		value, err := mtv.modec.ReadInt16()
 		if err != nil {
diff --git a/go/src/v.io/x/mojo/transcoder/target.go b/go/src/v.io/x/mojo/transcoder/target.go
index ba34c2d..ea0394c 100644
--- a/go/src/v.io/x/mojo/transcoder/target.go
+++ b/go/src/v.io/x/mojo/transcoder/target.go
@@ -45,6 +45,8 @@
 }
 func (t target) FromInt(src int64, tt *vdl.Type) error {
 	switch tt.Kind() {
+	case vdl.Int8:
+		t.current.Bytes()[0] = byte(src)
 	case vdl.Int16:
 		binary.LittleEndian.PutUint16(t.current.Bytes(), uint16(src))
 	case vdl.Int32:
@@ -170,23 +172,37 @@
 	st := target{
 		current: pointerBlock.Slice(0, 8),
 	}
-	setTarget, err := st.StartSet(vdl.SetType(tt.Key()), len)
+	keys, err := st.StartSet(vdl.SetType(tt.Key()), len)
 	if err != nil {
 		return nil, err
 	}
-	lt := target{
+	valuePlaceholder := target{
 		current: pointerBlock.Slice(8, 16),
 	}
-	listTarget, err := lt.StartList(vdl.ListType(tt.Elem()), len)
-	if err != nil {
-		return nil, err
-	}
 	return &mapTarget{
-		setTarget:  setTarget,
-		listTarget: listTarget,
+		keys:             keys,
+		valuePlaceholder: valuePlaceholder,
+		valueType:        tt.Elem(),
 	}, nil
 }
 func (t target) FinishMap(x vdl.MapTarget) error {
+	mt := x.(*mapTarget)
+	listTarget, err := mt.valuePlaceholder.StartList(vdl.ListType(mt.valueType), len(mt.cachedValues))
+	if err != nil {
+		return err
+	}
+	for i, val := range mt.cachedValues {
+		te, err := listTarget.StartElem(i)
+		if err != nil {
+			return err
+		}
+		if err := vdl.FromValue(te, val); err != nil {
+			return err
+		}
+		if err := listTarget.FinishElem(te); err != nil {
+			return err
+		}
+	}
 	return nil
 }
 func (t target) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error) {
diff --git a/go/src/v.io/x/mojo/transcoder/testdata_test.go b/go/src/v.io/x/mojo/transcoder/testdata_test.go
index 505246c..49cf269 100644
--- a/go/src/v.io/x/mojo/transcoder/testdata_test.go
+++ b/go/src/v.io/x/mojo/transcoder/testdata_test.go
@@ -7,6 +7,11 @@
 import (
 	"mojo/public/interfaces/bindings/tests/rect"
 	"mojo/public/interfaces/bindings/tests/test_structs"
+	"mojo/public/interfaces/bindings/tests/test_unions"
+
+	"mojom/tests/transcoder_testcases"
+
+	"v.io/x/mojo/transcoder/testtypes"
 )
 
 type transcodeTestCase struct {
@@ -68,7 +73,23 @@
 	// TODO(bprosnitz) HandleStruct?
 	// TODO(bprosnitz) NullableHandleStruct?
 	// TODO(bprosnitz) NoDefaultFieldValues?
-	// TODO(bprosnitz) DefaultFieldValues?
+	{
+		Name: "DefaultFieldValues",
+		MojoValue: &test_structs.DefaultFieldValues{
+			true, 100, 100, 100, 100, 100, 100, 100, 100,
+			100, 100, 100, 100,
+			"foo", stringPtr("foo"),
+			rect.Rect{X: 0, Y: 1, Height: 2, Width: 3},
+			&rect.Rect{X: 4, Y: 5, Height: 6, Width: 7},
+		},
+		VdlValue: test_structs.DefaultFieldValues{
+			true, 100, 100, 100, 100, 100, 100, 100, 100,
+			100, 100, 100, 100,
+			"foo", stringPtr("foo"),
+			rect.Rect{X: 0, Y: 1, Height: 2, Width: 3},
+			&rect.Rect{X: 4, Y: 5, Height: 6, Width: 7},
+		},
+	},
 	{
 		Name: "ScopedConstants",
 		MojoValue: &test_structs.ScopedConstants{
@@ -90,37 +111,57 @@
 			10,
 		},
 	},
-	// TODO(bprosnitz) MapKeyTypes?
+	{
+		Name: "MapKeyTypes",
+		MojoValue: &test_structs.MapKeyTypes{
+			map[bool]bool{true: false},
+			map[int8]int8{-1: 1},
+			map[uint8]uint8{1: 1},
+			map[int16]int16{-2: 2},
+			map[uint16]uint16{2: 2},
+			map[int32]int32{-4: 4},
+			map[uint32]uint32{4: 4},
+			map[int64]int64{-8: 8},
+			map[uint64]uint64{8: 8},
+			map[float32]float32{0.1: 0.1},
+			map[float64]float64{0.2: 0.2},
+			map[string]string{"A": "B", "C": "D"},
+		},
+		VdlValue: test_structs.MapKeyTypes{
+			map[bool]bool{true: false},
+			map[int8]int8{-1: 1},
+			map[uint8]uint8{1: 1},
+			map[int16]int16{-2: 2},
+			map[uint16]uint16{2: 2},
+			map[int32]int32{-4: 4},
+			map[uint32]uint32{4: 4},
+			map[int64]int64{-8: 8},
+			map[uint64]uint64{8: 8},
+			map[float32]float32{0.1: 0.1},
+			map[float64]float64{0.2: 0.2},
+			map[string]string{"A": "B", "C": "D"},
+		},
+	},
 	// TODO(bprosnitz) MapValueTypes?
-	// TODO(bprosnitz) ArrayValueTypes?
-	/*
-		{
-			Name: "UnsignedArrayValueTypes",
-			MojoValue: &test_structs.UnsignedArrayValueTypes{
-				[]uint8{1}, []uint16{2}, []uint32{3}, []uint64{4}, []float32{5}, []float64{6},
-			},
-			VdlValue: test_structs.UnsignedArrayValueTypes{
-				[]uint8{1}, []uint16{2}, []uint32{3}, []uint64{4}, []float32{5}, []float64{6},
-			},
+	{
+		Name: "ArrayValueTypes",
+		MojoValue: &test_structs.ArrayValueTypes{
+			[]int8{1},
+			[]int16{1, 2},
+			[]int32{1, 2, 3},
+			[]int64{1, 2, 3, 4},
+			[]float32{1},
+			[]float64{1, 2},
 		},
-		{
-			Name: "UnsignedFixedArrayValueTypes",
-			MojoValue: &test_structs.UnsignedFixedArrayValueTypes{
-				[3]uint8{1}, [2]uint16{2}, [2]uint32{3}, [2]uint64{4}, [2]float32{5}, [2]float64{6},
-			},
-			VdlValue: test_structs.UnsignedFixedArrayValueTypes{
-				[3]uint8{1}, [2]uint16{2}, [2]uint32{3}, [2]uint64{4}, [2]float32{5}, [2]float64{6},
-			},
+		VdlValue: test_structs.ArrayValueTypes{
+			[]int8{1},
+			[]int16{1, 2},
+			[]int32{1, 2, 3},
+			[]int64{1, 2, 3, 4},
+			[]float32{1},
+			[]float64{1, 2},
 		},
-		{
-			Name: "BoolArrayValueTypes",
-			MojoValue: &test_structs.BoolArrayValueTypes{
-				[]bool{false, true, true, false},
-			},
-			VdlValue: test_structs.BoolArrayValueTypes{
-				[]bool{false, true, true, false},
-			},
-		},*/
+	},
 	{
 		Name: "FloatNumberValues",
 		MojoValue: &test_structs.FloatNumberValues{
@@ -130,7 +171,15 @@
 			0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9,
 		},
 	},
-	// TODO(bprosnitz) IntegerNumberValues?
+	{
+		Name: "IntegerNumberValues",
+		MojoValue: &test_structs.IntegerNumberValues{
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+		},
+		VdlValue: test_structs.IntegerNumberValues{
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+		},
+	},
 	{
 		Name: "UnsignedNumberValues",
 		MojoValue: &test_structs.UnsignedNumberValues{
@@ -151,17 +200,71 @@
 			[][]bool{[]bool{true, false, true}}, []*[]bool{&[]bool{true, false, true}}, []*[2]bool{&[2]bool{true, false}},
 		},
 	},
-	// TODO(bprosnitz) MultiVersionStruct? + other versions
+	// TODO(bprosnitz) Multi-version structs are not yet supported because the version is specified in the
+	// struct header in the mojom bytes and we don't have any way to specify the version with VDL.
+	/*
+		{
+			Name: "MultiVersionStruct Full -> V3",
+			MojoValue: &test_structs.MultiVersionStruct{
+				FInt32:  8,
+				FRect:   &rect.Rect{1, 2, 3, 4},
+				FString: stringPtr("testStr"),
+			},
+			VdlValue: testtypes.MultiVersionStructV3{
+				FInt32:  8,
+				FRect:   testtypes.Rect{1, 2, 3, 4},
+				FString: "testStr",
+			},
+		},
+		{
+				Name: "MultiVersionStruct V3 -> Full",
+				MojoValue: &test_structs.MultiVersionStructV3{
+					FInt32:  8,
+					FRect:   &rect.Rect{1, 2, 3, 4},
+					FString: stringPtr("testStr"),
+				},
+				VdlValue: testtypes.MultiVersionStruct{
+					FInt32:  8,
+					FRect:   testtypes.Rect{1, 2, 3, 4},
+					FString: "testStr",
+				},
+			},*/
 	// from Mojo's test_unions
-	// TODO(bprosnitz) PodUnion?
-	// TODO(bprosnitz) ObjectUnion?
+	{
+		Name:      "PodUnionFInt8",
+		MojoValue: &transcoder_testcases.PodUnionWrapper{&test_unions.PodUnionFInt8{-1}},
+		VdlValue:  testtypes.PodUnionWrapper{testtypes.PodUnionFInt8{-1}},
+	},
+	{
+		Name:      "ObjectUnionFInt8",
+		MojoValue: &transcoder_testcases.ObjectUnionWrapper{&test_unions.ObjectUnionFInt8{5}},
+		VdlValue:  testtypes.ObjectUnionWrapper{testtypes.ObjectUnionFInt8{5}},
+	},
+	{
+		Name:      "ObjectUnionFDummy",
+		MojoValue: &transcoder_testcases.ObjectUnionWrapper{&test_unions.ObjectUnionFDummy{test_unions.DummyStruct{5}}},
+		VdlValue:  testtypes.ObjectUnionWrapper{testtypes.ObjectUnionFDummy{testtypes.DummyStruct{5}}},
+	},
+	{
+		Name:      "ObjectUnionFPodUnion",
+		MojoValue: &transcoder_testcases.ObjectUnionWrapper{&test_unions.ObjectUnionFPodUnion{&test_unions.PodUnionFDouble{1}}},
+		VdlValue:  testtypes.ObjectUnionWrapper{testtypes.ObjectUnionFPodUnion{testtypes.PodUnionFDouble{1}}},
+	},
 	// TODO(bprosnitz) HandleUnion?
 	// TODO(bprosnitz) WrapperStruct?
-	// TODO(bprosnitz) DummyStruct?
 	// TODO(bprosnitz) SmallStruct?
 	// TODO(bprosnitz) SmallStructNonNullableUnion?
 	// TODO(bprosnitz) SmallObjStruct?
-	// TODO(bprosnitz) TryNonNullStruct?
+	{
+		Name:      "TryNonNullStruct - nil optional",
+		MojoValue: &test_unions.TryNonNullStruct{},
+		VdlValue:  test_unions.TryNonNullStruct{},
+	},
+	{
+		Name:      "TryNonNullStruct - non nil optional",
+		MojoValue: &test_unions.TryNonNullStruct{&test_unions.DummyStruct{1}, test_unions.DummyStruct{2}},
+		VdlValue:  test_unions.TryNonNullStruct{&test_unions.DummyStruct{1}, test_unions.DummyStruct{2}},
+	},
 	// TODO(bprosnitz) OldUnion?
 	// TODO(bprosnitz) NewUnion?
 	// TODO(bprosnitz) IncludingStruct?
diff --git a/go/src/v.io/x/mojo/transcoder/testtypes/testtypes_test.vdl b/go/src/v.io/x/mojo/transcoder/testtypes/testtypes_test.vdl
new file mode 100644
index 0000000..ae9be70
--- /dev/null
+++ b/go/src/v.io/x/mojo/transcoder/testtypes/testtypes_test.vdl
@@ -0,0 +1,66 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testtypes
+
+type AnEnum enum{
+  First; Second
+}
+
+type PodUnion union {
+  FInt8 int8
+  FInt8Other int8
+  FUint8 byte
+  FInt16 int16
+  FUint16 uint16
+  Fint32 int32
+  Fuint32 uint32
+  FInt64 int64
+  FUint64 uint64
+  FFloat float32
+  FDouble float64
+  FBool bool
+  FEnum AnEnum
+}
+
+type PodUnionWrapper struct {
+    PodUnion PodUnion
+}
+
+type DummyStruct struct {
+    FInt8 int8
+}
+
+type ObjectUnion union {
+    FInt8 int8
+    FString string
+    FDummy DummyStruct
+    FNullable ?DummyStruct
+    FArrayInt8 []int8
+    FMapInt8 map[string]int8
+    FPodUnion PodUnion
+}
+
+type ObjectUnionWrapper struct {
+    ObjectUnion ObjectUnion
+}
+
+type Rect struct {
+    X,Y,Width,Height int32
+}
+
+type MultiVersionStruct struct {
+	FInt32 int32
+	FRect Rect
+	FString string
+	FArray []int8
+	FBool bool
+	FInt16 int16
+}
+
+type MultiVersionStructV3 struct {
+	FInt32 int32
+	FRect Rect
+	FString string
+}
\ No newline at end of file
diff --git a/go/src/v.io/x/mojo/transcoder/testtypes/testtypes_test.vdl.go b/go/src/v.io/x/mojo/transcoder/testtypes/testtypes_test.vdl.go
new file mode 100644
index 0000000..2f03420
--- /dev/null
+++ b/go/src/v.io/x/mojo/transcoder/testtypes/testtypes_test.vdl.go
@@ -0,0 +1,339 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file was auto-generated by the vanadium vdl tool.
+// Source: testtypes_test.vdl
+
+package testtypes
+
+import (
+	// VDL system imports
+	"fmt"
+	"v.io/v23/vdl"
+)
+
+type AnEnum int
+
+const (
+	AnEnumFirst AnEnum = iota
+	AnEnumSecond
+)
+
+// AnEnumAll holds all labels for AnEnum.
+var AnEnumAll = [...]AnEnum{AnEnumFirst, AnEnumSecond}
+
+// AnEnumFromString creates a AnEnum from a string label.
+func AnEnumFromString(label string) (x AnEnum, err error) {
+	err = x.Set(label)
+	return
+}
+
+// Set assigns label to x.
+func (x *AnEnum) Set(label string) error {
+	switch label {
+	case "First", "first":
+		*x = AnEnumFirst
+		return nil
+	case "Second", "second":
+		*x = AnEnumSecond
+		return nil
+	}
+	*x = -1
+	return fmt.Errorf("unknown label %q in testtypes.AnEnum", label)
+}
+
+// String returns the string label of x.
+func (x AnEnum) String() string {
+	switch x {
+	case AnEnumFirst:
+		return "First"
+	case AnEnumSecond:
+		return "Second"
+	}
+	return ""
+}
+
+func (AnEnum) __VDLReflect(struct {
+	Name string `vdl:"src/v.io/x/mojo/transcoder/testtypes.AnEnum"`
+	Enum struct{ First, Second string }
+}) {
+}
+
+type (
+	// PodUnion represents any single field of the PodUnion union type.
+	PodUnion interface {
+		// Index returns the field index.
+		Index() int
+		// Interface returns the field value as an interface.
+		Interface() interface{}
+		// Name returns the field name.
+		Name() string
+		// __VDLReflect describes the PodUnion union type.
+		__VDLReflect(__PodUnionReflect)
+	}
+	// PodUnionFInt8 represents field FInt8 of the PodUnion union type.
+	PodUnionFInt8 struct{ Value int8 }
+	// PodUnionFInt8Other represents field FInt8Other of the PodUnion union type.
+	PodUnionFInt8Other struct{ Value int8 }
+	// PodUnionFUint8 represents field FUint8 of the PodUnion union type.
+	PodUnionFUint8 struct{ Value byte }
+	// PodUnionFInt16 represents field FInt16 of the PodUnion union type.
+	PodUnionFInt16 struct{ Value int16 }
+	// PodUnionFUint16 represents field FUint16 of the PodUnion union type.
+	PodUnionFUint16 struct{ Value uint16 }
+	// PodUnionFint32 represents field Fint32 of the PodUnion union type.
+	PodUnionFint32 struct{ Value int32 }
+	// PodUnionFuint32 represents field Fuint32 of the PodUnion union type.
+	PodUnionFuint32 struct{ Value uint32 }
+	// PodUnionFInt64 represents field FInt64 of the PodUnion union type.
+	PodUnionFInt64 struct{ Value int64 }
+	// PodUnionFUint64 represents field FUint64 of the PodUnion union type.
+	PodUnionFUint64 struct{ Value uint64 }
+	// PodUnionFFloat represents field FFloat of the PodUnion union type.
+	PodUnionFFloat struct{ Value float32 }
+	// PodUnionFDouble represents field FDouble of the PodUnion union type.
+	PodUnionFDouble struct{ Value float64 }
+	// PodUnionFBool represents field FBool of the PodUnion union type.
+	PodUnionFBool struct{ Value bool }
+	// PodUnionFEnum represents field FEnum of the PodUnion union type.
+	PodUnionFEnum struct{ Value AnEnum }
+	// __PodUnionReflect describes the PodUnion union type.
+	__PodUnionReflect struct {
+		Name  string `vdl:"src/v.io/x/mojo/transcoder/testtypes.PodUnion"`
+		Type  PodUnion
+		Union struct {
+			FInt8      PodUnionFInt8
+			FInt8Other PodUnionFInt8Other
+			FUint8     PodUnionFUint8
+			FInt16     PodUnionFInt16
+			FUint16    PodUnionFUint16
+			Fint32     PodUnionFint32
+			Fuint32    PodUnionFuint32
+			FInt64     PodUnionFInt64
+			FUint64    PodUnionFUint64
+			FFloat     PodUnionFFloat
+			FDouble    PodUnionFDouble
+			FBool      PodUnionFBool
+			FEnum      PodUnionFEnum
+		}
+	}
+)
+
+func (x PodUnionFInt8) Index() int                     { return 0 }
+func (x PodUnionFInt8) Interface() interface{}         { return x.Value }
+func (x PodUnionFInt8) Name() string                   { return "FInt8" }
+func (x PodUnionFInt8) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFInt8Other) Index() int                     { return 1 }
+func (x PodUnionFInt8Other) Interface() interface{}         { return x.Value }
+func (x PodUnionFInt8Other) Name() string                   { return "FInt8Other" }
+func (x PodUnionFInt8Other) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFUint8) Index() int                     { return 2 }
+func (x PodUnionFUint8) Interface() interface{}         { return x.Value }
+func (x PodUnionFUint8) Name() string                   { return "FUint8" }
+func (x PodUnionFUint8) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFInt16) Index() int                     { return 3 }
+func (x PodUnionFInt16) Interface() interface{}         { return x.Value }
+func (x PodUnionFInt16) Name() string                   { return "FInt16" }
+func (x PodUnionFInt16) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFUint16) Index() int                     { return 4 }
+func (x PodUnionFUint16) Interface() interface{}         { return x.Value }
+func (x PodUnionFUint16) Name() string                   { return "FUint16" }
+func (x PodUnionFUint16) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFint32) Index() int                     { return 5 }
+func (x PodUnionFint32) Interface() interface{}         { return x.Value }
+func (x PodUnionFint32) Name() string                   { return "Fint32" }
+func (x PodUnionFint32) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFuint32) Index() int                     { return 6 }
+func (x PodUnionFuint32) Interface() interface{}         { return x.Value }
+func (x PodUnionFuint32) Name() string                   { return "Fuint32" }
+func (x PodUnionFuint32) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFInt64) Index() int                     { return 7 }
+func (x PodUnionFInt64) Interface() interface{}         { return x.Value }
+func (x PodUnionFInt64) Name() string                   { return "FInt64" }
+func (x PodUnionFInt64) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFUint64) Index() int                     { return 8 }
+func (x PodUnionFUint64) Interface() interface{}         { return x.Value }
+func (x PodUnionFUint64) Name() string                   { return "FUint64" }
+func (x PodUnionFUint64) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFFloat) Index() int                     { return 9 }
+func (x PodUnionFFloat) Interface() interface{}         { return x.Value }
+func (x PodUnionFFloat) Name() string                   { return "FFloat" }
+func (x PodUnionFFloat) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFDouble) Index() int                     { return 10 }
+func (x PodUnionFDouble) Interface() interface{}         { return x.Value }
+func (x PodUnionFDouble) Name() string                   { return "FDouble" }
+func (x PodUnionFDouble) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFBool) Index() int                     { return 11 }
+func (x PodUnionFBool) Interface() interface{}         { return x.Value }
+func (x PodUnionFBool) Name() string                   { return "FBool" }
+func (x PodUnionFBool) __VDLReflect(__PodUnionReflect) {}
+
+func (x PodUnionFEnum) Index() int                     { return 12 }
+func (x PodUnionFEnum) Interface() interface{}         { return x.Value }
+func (x PodUnionFEnum) Name() string                   { return "FEnum" }
+func (x PodUnionFEnum) __VDLReflect(__PodUnionReflect) {}
+
+type PodUnionWrapper struct {
+	PodUnion PodUnion
+}
+
+func (PodUnionWrapper) __VDLReflect(struct {
+	Name string `vdl:"src/v.io/x/mojo/transcoder/testtypes.PodUnionWrapper"`
+}) {
+}
+
+type DummyStruct struct {
+	FInt8 int8
+}
+
+func (DummyStruct) __VDLReflect(struct {
+	Name string `vdl:"src/v.io/x/mojo/transcoder/testtypes.DummyStruct"`
+}) {
+}
+
+type (
+	// ObjectUnion represents any single field of the ObjectUnion union type.
+	ObjectUnion interface {
+		// Index returns the field index.
+		Index() int
+		// Interface returns the field value as an interface.
+		Interface() interface{}
+		// Name returns the field name.
+		Name() string
+		// __VDLReflect describes the ObjectUnion union type.
+		__VDLReflect(__ObjectUnionReflect)
+	}
+	// ObjectUnionFInt8 represents field FInt8 of the ObjectUnion union type.
+	ObjectUnionFInt8 struct{ Value int8 }
+	// ObjectUnionFString represents field FString of the ObjectUnion union type.
+	ObjectUnionFString struct{ Value string }
+	// ObjectUnionFDummy represents field FDummy of the ObjectUnion union type.
+	ObjectUnionFDummy struct{ Value DummyStruct }
+	// ObjectUnionFNullable represents field FNullable of the ObjectUnion union type.
+	ObjectUnionFNullable struct{ Value *DummyStruct }
+	// ObjectUnionFArrayInt8 represents field FArrayInt8 of the ObjectUnion union type.
+	ObjectUnionFArrayInt8 struct{ Value []int8 }
+	// ObjectUnionFMapInt8 represents field FMapInt8 of the ObjectUnion union type.
+	ObjectUnionFMapInt8 struct{ Value map[string]int8 }
+	// ObjectUnionFPodUnion represents field FPodUnion of the ObjectUnion union type.
+	ObjectUnionFPodUnion struct{ Value PodUnion }
+	// __ObjectUnionReflect describes the ObjectUnion union type.
+	__ObjectUnionReflect struct {
+		Name  string `vdl:"src/v.io/x/mojo/transcoder/testtypes.ObjectUnion"`
+		Type  ObjectUnion
+		Union struct {
+			FInt8      ObjectUnionFInt8
+			FString    ObjectUnionFString
+			FDummy     ObjectUnionFDummy
+			FNullable  ObjectUnionFNullable
+			FArrayInt8 ObjectUnionFArrayInt8
+			FMapInt8   ObjectUnionFMapInt8
+			FPodUnion  ObjectUnionFPodUnion
+		}
+	}
+)
+
+func (x ObjectUnionFInt8) Index() int                        { return 0 }
+func (x ObjectUnionFInt8) Interface() interface{}            { return x.Value }
+func (x ObjectUnionFInt8) Name() string                      { return "FInt8" }
+func (x ObjectUnionFInt8) __VDLReflect(__ObjectUnionReflect) {}
+
+func (x ObjectUnionFString) Index() int                        { return 1 }
+func (x ObjectUnionFString) Interface() interface{}            { return x.Value }
+func (x ObjectUnionFString) Name() string                      { return "FString" }
+func (x ObjectUnionFString) __VDLReflect(__ObjectUnionReflect) {}
+
+func (x ObjectUnionFDummy) Index() int                        { return 2 }
+func (x ObjectUnionFDummy) Interface() interface{}            { return x.Value }
+func (x ObjectUnionFDummy) Name() string                      { return "FDummy" }
+func (x ObjectUnionFDummy) __VDLReflect(__ObjectUnionReflect) {}
+
+func (x ObjectUnionFNullable) Index() int                        { return 3 }
+func (x ObjectUnionFNullable) Interface() interface{}            { return x.Value }
+func (x ObjectUnionFNullable) Name() string                      { return "FNullable" }
+func (x ObjectUnionFNullable) __VDLReflect(__ObjectUnionReflect) {}
+
+func (x ObjectUnionFArrayInt8) Index() int                        { return 4 }
+func (x ObjectUnionFArrayInt8) Interface() interface{}            { return x.Value }
+func (x ObjectUnionFArrayInt8) Name() string                      { return "FArrayInt8" }
+func (x ObjectUnionFArrayInt8) __VDLReflect(__ObjectUnionReflect) {}
+
+func (x ObjectUnionFMapInt8) Index() int                        { return 5 }
+func (x ObjectUnionFMapInt8) Interface() interface{}            { return x.Value }
+func (x ObjectUnionFMapInt8) Name() string                      { return "FMapInt8" }
+func (x ObjectUnionFMapInt8) __VDLReflect(__ObjectUnionReflect) {}
+
+func (x ObjectUnionFPodUnion) Index() int                        { return 6 }
+func (x ObjectUnionFPodUnion) Interface() interface{}            { return x.Value }
+func (x ObjectUnionFPodUnion) Name() string                      { return "FPodUnion" }
+func (x ObjectUnionFPodUnion) __VDLReflect(__ObjectUnionReflect) {}
+
+type ObjectUnionWrapper struct {
+	ObjectUnion ObjectUnion
+}
+
+func (ObjectUnionWrapper) __VDLReflect(struct {
+	Name string `vdl:"src/v.io/x/mojo/transcoder/testtypes.ObjectUnionWrapper"`
+}) {
+}
+
+type Rect struct {
+	X      int32
+	Y      int32
+	Width  int32
+	Height int32
+}
+
+func (Rect) __VDLReflect(struct {
+	Name string `vdl:"src/v.io/x/mojo/transcoder/testtypes.Rect"`
+}) {
+}
+
+type MultiVersionStruct struct {
+	FInt32  int32
+	FRect   Rect
+	FString string
+	FArray  []int8
+	FBool   bool
+	FInt16  int16
+}
+
+func (MultiVersionStruct) __VDLReflect(struct {
+	Name string `vdl:"src/v.io/x/mojo/transcoder/testtypes.MultiVersionStruct"`
+}) {
+}
+
+type MultiVersionStructV3 struct {
+	FInt32  int32
+	FRect   Rect
+	FString string
+}
+
+func (MultiVersionStructV3) __VDLReflect(struct {
+	Name string `vdl:"src/v.io/x/mojo/transcoder/testtypes.MultiVersionStructV3"`
+}) {
+}
+
+func init() {
+	vdl.Register((*AnEnum)(nil))
+	vdl.Register((*PodUnion)(nil))
+	vdl.Register((*PodUnionWrapper)(nil))
+	vdl.Register((*DummyStruct)(nil))
+	vdl.Register((*ObjectUnion)(nil))
+	vdl.Register((*ObjectUnionWrapper)(nil))
+	vdl.Register((*Rect)(nil))
+	vdl.Register((*MultiVersionStruct)(nil))
+	vdl.Register((*MultiVersionStructV3)(nil))
+}
diff --git a/go/src/v.io/x/mojo/transcoder/transcoder_test.go b/go/src/v.io/x/mojo/transcoder/transcoder_test.go
index 7edb85e..0c634e3 100644
--- a/go/src/v.io/x/mojo/transcoder/transcoder_test.go
+++ b/go/src/v.io/x/mojo/transcoder/transcoder_test.go
@@ -5,15 +5,12 @@
 package transcoder_test
 
 import (
+	"fmt"
 	"reflect"
 	"testing"
 
 	"mojo/public/go/bindings"
 
-	"fmt"
-
-	"bytes"
-
 	"v.io/v23/vdl"
 	"v.io/x/mojo/transcoder"
 )
@@ -22,7 +19,7 @@
 	for _, test := range testCases {
 		testName := test.Name + " mojo->vom"
 
-		data, err := computeExpectedMojomBytes(test.MojoValue)
+		data, err := mojoEncode(test.MojoValue)
 		if err != nil {
 			t.Errorf("%s: %v", testName, err)
 			continue
@@ -50,20 +47,20 @@
 			continue
 		}
 
-		expectedData, err := computeExpectedMojomBytes(test.MojoValue)
-		if err != nil {
-			t.Errorf("%s: %v", testName, err)
+		out := reflect.New(reflect.TypeOf(test.MojoValue).Elem()).Interface()
+		if err := mojoDecode(data, out); err != nil {
+			t.Errorf("%s: error decoding mojo bytes %x: %v", testName, data, err)
 			continue
 		}
 
-		if got, want := data, expectedData; !bytes.Equal(got, want) {
-			t.Errorf("%s: got %x, but want %x", testName, got, want)
+		if got, want := out, test.MojoValue; !reflect.DeepEqual(got, want) {
+			t.Errorf("%s: result doesn't match expectation. got %#v, but want %#v", testName, got, want)
 		}
 	}
 }
 
-func computeExpectedMojomBytes(mojoValue interface{}) ([]byte, error) {
-	payload, ok := mojoValue.(bindings.Payload)
+func mojoEncode(mojoValue interface{}) ([]byte, error) {
+	payload, ok := mojoValue.(encodable)
 	if !ok {
 		return nil, fmt.Errorf("type %T lacks an Encode() method", mojoValue)
 	}
@@ -79,3 +76,20 @@
 	}
 	return data, nil
 }
+
+func mojoDecode(b []byte, outValue interface{}) error {
+	dec := bindings.NewDecoder(b, nil)
+	payload, ok := outValue.(decodable)
+	if !ok {
+		return fmt.Errorf("type %T lacks an Decode() method", outValue)
+	}
+	return payload.Decode(dec)
+}
+
+type encodable interface {
+	Encode(encoder *bindings.Encoder) error
+}
+
+type decodable interface {
+	Decode(decoder *bindings.Decoder) error
+}
diff --git a/go/src/v.io/x/mojo/transcoder/typed_targets.go b/go/src/v.io/x/mojo/transcoder/typed_targets.go
index f343bb8..4bec230 100644
--- a/go/src/v.io/x/mojo/transcoder/typed_targets.go
+++ b/go/src/v.io/x/mojo/transcoder/typed_targets.go
@@ -112,15 +112,20 @@
 }
 
 type mapTarget struct {
-	listTarget vdl.ListTarget
-	setTarget  vdl.SetTarget
+	keys             vdl.SetTarget
+	valuePlaceholder vdl.Target
+	valueType        *vdl.Type
+	cachedValues     []*vdl.Value
 }
 
 func (mt *mapTarget) StartKey() (key vdl.Target, _ error) {
-	return mt.setTarget.StartKey()
+	return mt.keys.StartKey()
 }
-func (mt *mapTarget) FinishKeyStartField(key vdl.Target) (field vdl.Target, _ error) {
-	return mt.listTarget.StartElem(0)
+func (mt *mapTarget) FinishKeyStartField(key vdl.Target) (field vdl.Target, err error) {
+	val := vdl.ZeroValue(mt.valueType)
+	field, err = vdl.ValueTarget(val)
+	mt.cachedValues = append(mt.cachedValues, val)
+	return
 }
 func (mapTarget) FinishField(key, field vdl.Target) error {
 	return nil
diff --git a/go/src/v.io/x/mojo/transcoder/vdl_to_mojom.go b/go/src/v.io/x/mojo/transcoder/vdl_to_mojom.go
index 0a0bca6..53fe3dc 100644
--- a/go/src/v.io/x/mojo/transcoder/vdl_to_mojom.go
+++ b/go/src/v.io/x/mojo/transcoder/vdl_to_mojom.go
@@ -81,10 +81,7 @@
 }
 func (vtm *vdlToMojomTranscoder) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error) {
 	if tt.Kind() == vdl.Union {
-		panic("not yet supported")
-	}
-	if tt.Kind() == vdl.Optional {
-		tt = tt.Elem()
+		panic("UNIMPLEMENTED")
 	}
 	block := vtm.allocator.Allocate(neededStructAllocationSize(tt), 0)
 	return fieldsTarget{
diff --git a/mojom/mojom/tests/transcoder_testcases.mojom b/mojom/mojom/tests/transcoder_testcases.mojom
index 61ae4f8..0363430 100644
--- a/mojom/mojom/tests/transcoder_testcases.mojom
+++ b/mojom/mojom/tests/transcoder_testcases.mojom
@@ -4,9 +4,20 @@
 
 module tests;
 
+import "mojo/public/interfaces/bindings/tests/test_unions.mojom";
+
 struct UnnamedPrimitiveTestStruct {
     uint32 A;
     string B;
     bool C;
     float D;
-};
\ No newline at end of file
+};
+
+struct PodUnionWrapper {
+  mojo.test.PodUnion pod_union;
+};
+
+
+struct ObjectUnionWrapper {
+  mojo.test.ObjectUnion object_union;
+};