Add extra entries to vdltest.AllPass and vdltest.AllFail

The extra entries are the top-level union interface, the
top-level error interface, and a variety of extra pointer tests.

Change-Id: I3dc003a042d1a16ae393e8bd3bdc36e18cb3ac1f
diff --git a/vdl/.api b/vdl/.api
index d96c09f..56704dd 100644
--- a/vdl/.api
+++ b/vdl/.api
@@ -72,6 +72,7 @@
 pkg vdl, func ValueOf(interface{}) *Value
 pkg vdl, func ValueTarget(*Value) (Target, error)
 pkg vdl, func WireRetryCodeFromString(string) (WireRetryCode, error)
+pkg vdl, func WrapInUnionInterface(reflect.Value) reflect.Value
 pkg vdl, func Write(Encoder, interface{}) error
 pkg vdl, func WriteReflect(Encoder, reflect.Value) error
 pkg vdl, func ZeroValue(*Type) *Value
diff --git a/vdl/reflect_reader.go b/vdl/reflect_reader.go
index b20277d..a1afa65 100644
--- a/vdl/reflect_reader.go
+++ b/vdl/reflect_reader.go
@@ -197,10 +197,7 @@
 	}
 	// Lookup the reflect type based on the decoder type, and create a new value
 	// to decode into.
-	//
-	// TODO(toddw): Replace typeToReflectFixed with TypeToReflect, after we've
-	// fixed it to treat the error type correctly.
-	rtDecode := typeToReflectFixed(dec.Type())
+	rtDecode := TypeToReflect(dec.Type())
 	if rtDecode == nil {
 		return fmt.Errorf("vdl: %v not registered, call vdl.Register, or use vdl.Value or vom.RawBytes instead", dec.Type())
 	}
diff --git a/vdl/register.go b/vdl/register.go
index f722f7b..587c0d7 100644
--- a/vdl/register.go
+++ b/vdl/register.go
@@ -120,6 +120,24 @@
 	return ri
 }
 
+// WrapInUnionInterface returns a value of the union interface type that holds
+// the union value rv.  Returns an invalid reflect.Value if rv isn't a union
+// value.  Returns rv unchanged if its type is already the interface type.
+func WrapInUnionInterface(rv reflect.Value) reflect.Value {
+	ri, _, err := deriveReflectInfo(rv.Type())
+	switch {
+	case err != nil || len(ri.UnionFields) == 0:
+		return reflect.Value{} // rv isn't a union
+	case ri.Type == rv.Type():
+		return rv // rv's type is already the interface type
+	}
+	// Here ri.Type is the union interface type, while rv is a concrete struct
+	// type.  Wrap rv in a value of the interface type.
+	rvIface := reflect.New(ri.Type).Elem()
+	rvIface.Set(rv)
+	return rvIface
+}
+
 // reflectInfo holds the reflection information for a type.  All fields are
 // populated via reflection over the Type.
 //
@@ -377,9 +395,6 @@
 // named types in our registry, and build the unnamed types that we can via the
 // Go reflect package.  Returns nil for types that can't be manufactured.
 func TypeToReflect(t *Type) reflect.Type {
-	// TODO(toddw): This is broken, since it doesn't handle registered native
-	// error types correctly.  But it's hard to fix with the old convert.go logic,
-	// so we'll wait until we get rid of that code completely.
 	if t.Name() != "" {
 		// Named types cannot be manufactured via Go reflect, so we lookup in our
 		// registry instead.
@@ -431,60 +446,6 @@
 	}
 }
 
-// TODO(toddw): Replace TypeToReflect with typeToReflectFixed after the old
-// conversion logic is removed.
-func typeToReflectFixed(t *Type) reflect.Type {
-	if t.Name() != "" {
-		// Named types cannot be manufactured via Go reflect, so we lookup in our
-		// registry instead.
-		if ri := reflectInfoFromName(t.Name()); ri != nil {
-			if ni := nativeInfoFromWire(ri.Type); ni != nil {
-				return ni.NativeType
-			}
-			return ri.Type
-		}
-		return nil
-	}
-	// We can make some unnamed types via Go reflect.  Return nil otherwise.
-	switch t.Kind() {
-	case Any, Enum, Union:
-		// We can't make unnamed versions of any of these types.
-		return nil
-	case Optional:
-		if elem := typeToReflectFixed(t.Elem()); elem != nil {
-			return reflect.PtrTo(elem)
-		}
-		return nil
-	case Array:
-		if elem := typeToReflectFixed(t.Elem()); elem != nil {
-			return reflect.ArrayOf(t.Len(), elem)
-		}
-		return nil
-	case List:
-		if elem := typeToReflectFixed(t.Elem()); elem != nil {
-			return reflect.SliceOf(elem)
-		}
-		return nil
-	case Set:
-		if key := typeToReflectFixed(t.Key()); key != nil {
-			return reflect.MapOf(key, rtUnnamedEmptyStruct)
-		}
-		return nil
-	case Map:
-		if key, elem := typeToReflectFixed(t.Key()), typeToReflectFixed(t.Elem()); key != nil && elem != nil {
-			return reflect.MapOf(key, elem)
-		}
-		return nil
-	case Struct:
-		if t.NumField() == 0 {
-			return rtUnnamedEmptyStruct
-		}
-		return nil
-	default:
-		return rtFromKind[t.Kind()]
-	}
-}
-
 var rtFromKind = [...]reflect.Type{
 	Bool:       rtBool,
 	Byte:       rtByte,
diff --git a/vdl/vdltest/all.go b/vdl/vdltest/all.go
index f1ee8e8..e4a152b 100644
--- a/vdl/vdltest/all.go
+++ b/vdl/vdltest/all.go
@@ -9,15 +9,24 @@
 	"flag"
 	"reflect"
 	"strings"
+
+	"v.io/v23/vdl"
 )
 
 // The following causes data files to be generated when "go generate" is run.
 //go:generate ./gen.sh
 
-var flagContains string
+var flagVDLTest string
 
 func init() {
-	flag.StringVar(&flagContains, "vdltest", "", "Filter vdltest.All to only return entries that contain the given substring.")
+	flag.StringVar(&flagVDLTest, "vdltest", "", `Filter vdltest.All to only return entries that contain the given substring.  If the value starts with "!", only returns entries that don't contain the given substring.`)
+}
+
+func filter() (bool, string) {
+	if strings.HasPrefix(flagVDLTest, "!") {
+		return false, strings.TrimPrefix(flagVDLTest, "!")
+	}
+	return true, flagVDLTest
 }
 
 // The following vars are defined in generated files:
@@ -30,7 +39,7 @@
 func AllPass() []Entry {
 	var result []Entry
 	for _, e := range fromVDLEntries(vAllPass, xAllPass) {
-		if strings.Contains(e.Name(), flagContains) {
+		if want, substr := filter(); strings.Contains(e.Name(), substr) == want {
 			result = append(result, e)
 		}
 	}
@@ -61,7 +70,7 @@
 func AllFail() []Entry {
 	var result []Entry
 	for _, e := range fromVDLEntries(vAllFail, xAllFail) {
-		if strings.Contains(e.Name(), flagContains) {
+		if want, substr := filter(); strings.Contains(e.Name(), substr) == want {
 			result = append(result, e)
 		}
 	}
@@ -84,15 +93,8 @@
 	var result []Entry
 	for _, entries := range groups {
 		for _, e := range entries {
-			entry := fromVDLEntry(e)
-			result = append(result, entry)
-			// TODO(toddw): add additional entries and pointer tests.
-			/*
-				switch ttTarget := vdl.TypeOf(e.Target); {
-				case ttTarget.Kind() == vdl.Union:
-				case ttTarget == vdl.ErrorType:
-				}
-			*/
+			result = append(result, fromVDLEntry(e))
+			result = append(result, genExtraEntries(e)...)
 		}
 	}
 	return result
@@ -103,8 +105,92 @@
 		IsCanonical: e.IsCanonical,
 		Label:       e.Label,
 		TargetLabel: e.TargetLabel,
-		Target:      reflect.ValueOf(e.Target),
+		Target:      rvSafeValueOf(e.Target),
 		SourceLabel: e.SourceLabel,
-		Source:      reflect.ValueOf(e.Source),
+		Source:      rvSafeValueOf(e.Source),
 	}
 }
+
+func rvSafeValueOf(v interface{}) reflect.Value {
+	// reflect.ValueOf(nil) returns an invalid reflect.Value, but we want a valid
+	// reflect.Value representing nil.
+	if v == nil {
+		return reflect.ValueOf(&v).Elem()
+	}
+	return reflect.ValueOf(v)
+}
+
+// genExtraEntries generates extra entries based on e.  None of these are
+// canonical; they all deal with quirks in the Go representation of VDL values.
+func genExtraEntries(e vdlEntry) []Entry {
+	var extra []Entry
+	switch ttTarget := vdl.TypeOf(e.Target); {
+	case ttTarget.Kind() == vdl.Union:
+		// Add entry for top-level union interface.
+		entry := fromVDLEntry(e)
+		entry.IsCanonical = false
+		entry.Label += " [union interface]"
+		entry.Target = vdl.WrapInUnionInterface(entry.Target)
+		entry.TargetLabel += " [interface]"
+		if vdl.TypeOf(e.Source).Kind() == vdl.Union {
+			entry.Source = vdl.WrapInUnionInterface(entry.Source)
+			entry.SourceLabel += " [interface]"
+		}
+		extra = append(extra, entry)
+	case ttTarget == vdl.ErrorType:
+		// Add entry for top-level error interface.
+		entry := fromVDLEntry(e)
+		entry.IsCanonical = false
+		entry.Label += " [error interface]"
+		entry.Target = rvWrapInErrorInterface(entry.Target)
+		entry.TargetLabel += " [interface]"
+		if vdl.TypeOf(e.Source) == vdl.ErrorType {
+			entry.Source = rvWrapInErrorInterface(entry.Source)
+			entry.SourceLabel += " [interface]"
+		}
+		extra = append(extra, entry)
+	}
+	// Add entries with up to 2 additional pointers on the target and source.
+	const maxPtrs = 2
+	for t := 0; t < maxPtrs; t++ {
+		for s := 0; s < maxPtrs; s++ {
+			if t == 0 && s == 0 {
+				continue // skip the 0,0 case, which is already represented by e
+			}
+			entry := fromVDLEntry(e)
+			entry.IsCanonical = false
+			entry.Label += " [pointers]"
+			entry.Target, entry.TargetLabel = rvAddPointers(t, entry.Target, entry.TargetLabel)
+			entry.Source, entry.SourceLabel = rvAddPointers(s, entry.Source, entry.SourceLabel)
+			extra = append(extra, entry)
+		}
+	}
+	return extra
+}
+
+var rtError = reflect.TypeOf((*error)(nil)).Elem()
+
+// rvWrapInErrorInterface returns a reflect.Value whose type is the Go error
+// interface, which is set to rv.
+//
+// REQUIRES: rv must implement the Go error interface
+func rvWrapInErrorInterface(rv reflect.Value) reflect.Value {
+	rvError := reflect.New(rtError).Elem()
+	if rv.Kind() != reflect.Ptr || !rv.IsNil() {
+		// Only set the value for non-nil pointers.  If rv is (*verror.E)(nil), we
+		// want to end up with Go error(nil).
+		rvError.Set(rv)
+	}
+	return rvError
+}
+
+// rvAddPointers adds num pointers to rv.
+func rvAddPointers(num int, rv reflect.Value, label string) (reflect.Value, string) {
+	for i := 0; i < num; i++ {
+		rvPtr := reflect.New(rv.Type())
+		rvPtr.Elem().Set(rv)
+		rv = rvPtr
+		label = "*" + label
+	}
+	return rv, label
+}
diff --git a/vdl/vdltest/internal/vdltestgen/doc.go b/vdl/vdltest/internal/vdltestgen/doc.go
index cdad5f0..01b4db4 100644
--- a/vdl/vdltest/internal/vdltestgen/doc.go
+++ b/vdl/vdltest/internal/vdltestgen/doc.go
@@ -48,5 +48,7 @@
    Dump timing information to stderr before exiting the program.
  -vdltest=
    Filter vdltest.All to only return entries that contain the given substring.
+   If the value starts with "!", only returns entries that don't contain the
+   given substring.
 */
 package main
diff --git a/vom/vomtest/data.go b/vom/vomtest/data.go
index 9602a1d..35963f2 100644
--- a/vom/vomtest/data.go
+++ b/vom/vomtest/data.go
@@ -14,17 +14,24 @@
 // The following causes data files to be generated when "go generate" is run.
 //go:generate ./gen.sh
 
-var flagContains string
+var flagVOMTest string
 
 func init() {
-	flag.StringVar(&flagContains, "vomtest", "", "Filter vomtest.Data to only return entries that contain the given substring.")
+	flag.StringVar(&flagVOMTest, "vomtest", "", `Filter vomtest.Data to only return entries that contain the given substring.  If the value starts with "!", only returns entries that don't contain the given substring.`)
+}
+
+func filter() (bool, string) {
+	if strings.HasPrefix(flagVOMTest, "!") {
+		return false, strings.TrimPrefix(flagVOMTest, "!")
+	}
+	return true, flagVOMTest
 }
 
 // Data returns all vom test cases.
 func Data() []TestCase {
 	var result []TestCase
 	for _, t := range data81 {
-		if strings.Contains(t.Name, flagContains) {
+		if want, substr := filter(); strings.Contains(t.Name, substr) == want {
 			result = append(result, t)
 		}
 	}
diff --git a/vom/vomtest/internal/vomtestgen/doc.go b/vom/vomtest/internal/vomtestgen/doc.go
index a7cfcf2..e07b085 100644
--- a/vom/vomtest/internal/vomtestgen/doc.go
+++ b/vom/vomtest/internal/vomtestgen/doc.go
@@ -32,5 +32,7 @@
    Dump timing information to stderr before exiting the program.
  -vdltest=
    Filter vdltest.All to only return entries that contain the given substring.
+   If the value starts with "!", only returns entries that don't contain the
+   given substring.
 */
 package main