cue: allow Len for invalid objects

Fixes #51.

Change-Id: I64cd6e782c8806724590fc4073ef8b7eb0c7affa
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2181
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/types.go b/cue/types.go
index a4a5c85..75637da 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -80,6 +80,9 @@
 
 // Len reports the number of fields in this struct.
 func (o *structValue) Len() int {
+	if o.n == nil {
+		return 0
+	}
 	return len(o.n.arcs)
 }
 
@@ -95,12 +98,13 @@
 func (o *structValue) Lookup(key string) Value {
 	f := o.ctx.strLabel(key)
 	i := 0
-	for ; i < len(o.n.arcs); i++ {
+	len := o.Len()
+	for ; i < len; i++ {
 		if o.n.arcs[i].feature == f {
 			break
 		}
 	}
-	if i == len(o.n.arcs) {
+	if i == len {
 		// TODO: better message.
 		return newValueRoot(o.ctx, o.ctx.mkErr(o.n, codeNotExist,
 			"value %q not found", key))
diff --git a/cue/types_test.go b/cue/types_test.go
index 895df3c..4df1cc3 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -993,6 +993,67 @@
 	}
 }
 
+func TestValidate(t *testing.T) {
+	testCases := []struct {
+		desc string
+		in   string
+		err  bool
+		opts []Option
+	}{{
+		desc: "issue #51",
+		in: `
+		a <Name>: foo
+		a b: {}
+		`,
+		err: true,
+	}, {
+		desc: "concrete",
+		in: `
+		a: 1
+		b: { c: 2, d: 3 }
+		c d e f: 5
+		`,
+		opts: []Option{Concrete(true)},
+	}, {
+		desc: "disjunction",
+		in:   `a: 1 | 2`,
+	}, {
+		desc: "disjunction concrete",
+		in:   `a: 1 | 2`,
+		opts: []Option{Concrete(true)},
+		err:  true,
+	}, {
+		desc: "incomplete concrete",
+		in:   `a: string`,
+	}, {
+		desc: "incomplete",
+		in:   `a: string`,
+		opts: []Option{Concrete(true)},
+		err:  true,
+	}, {
+		desc: "list",
+		in:   `a: [{b: string}, 3]`,
+	}, {
+		desc: "list concrete",
+		in:   `a: [{b: string}, 3]`,
+		opts: []Option{Concrete(true)},
+		err:  true,
+	}}
+	for _, tc := range testCases {
+		t.Run(tc.desc, func(t *testing.T) {
+			r := Runtime{}
+			inst, err := r.Parse("validate", tc.in)
+			if err != nil {
+				t.Fatal(err)
+			}
+			err = inst.Value().Validate(tc.opts...)
+			if gotErr := err != nil; gotErr != tc.err {
+				t.Errorf("got %v; want %v", err, tc.err)
+			}
+		})
+	}
+}
+
 func TestValueLookup(t *testing.T) {
 	config := `
 		a: {