go/bindings: update code to pass structs versions tests

Now we should verify struct data header
if we know the version.

R=jamesr@chromium.org

Review URL: https://codereview.chromium.org/948343008
diff --git a/mojo/go/tests/validation_test.go b/mojo/go/tests/validation_test.go
index d5fc1bc..c7499ff 100644
--- a/mojo/go/tests/validation_test.go
+++ b/mojo/go/tests/validation_test.go
@@ -295,6 +295,10 @@
 	return v.Proxy.Method10(inParam0)
 }
 
+func (v *conformanceValidator) Method11(inParam0 test.StructG) error {
+	return nil
+}
+
 func TestConformanceValidation(t *testing.T) {
 	tests := getMatchingTests(listTestFiles(), "conformance_")
 	waiter := bindings.GetAsyncWaiter()
diff --git a/mojo/public/go/bindings/decoder.go b/mojo/public/go/bindings/decoder.go
index 6f6b433..34a230e 100644
--- a/mojo/public/go/bindings/decoder.go
+++ b/mojo/public/go/bindings/decoder.go
@@ -125,22 +125,22 @@
 	return nil
 }
 
-// StartStruct starts decoding a struct and reads its data header,
-// returning struct version declared in data header.
+// StartStruct starts decoding a struct and reads its data header.
+// Returns the read data header. The caller should check if it is valid.
 // Note: it doesn't read a pointer to the encoded struct.
 // Call |Finish()| after reading all fields.
-func (d *Decoder) StartStruct() (uint32, error) {
+func (d *Decoder) StartStruct() (DataHeader, error) {
 	header, err := d.readDataHeader()
 	if err != nil {
-		return 0, err
+		return DataHeader{}, err
 	}
 	if header.Size < dataHeaderSize {
-		return 0, fmt.Errorf("data header size is too small: is %d, but should be at least %d", header.Size, dataHeaderSize)
+		return DataHeader{}, fmt.Errorf("data header size(%d) should be at least %d", header.Size, dataHeaderSize)
 	}
 	if err := d.pushState(header, 0); err != nil {
-		return 0, err
+		return DataHeader{}, err
 	}
-	return header.ElementsOrVersion, nil
+	return header, nil
 }
 
 func (d *Decoder) readDataHeader() (DataHeader, error) {
diff --git a/mojo/public/go/bindings/message.go b/mojo/public/go/bindings/message.go
index e5c8329..8455cd4 100644
--- a/mojo/public/go/bindings/message.go
+++ b/mojo/public/go/bindings/message.go
@@ -68,10 +68,11 @@
 }
 
 func (h *MessageHeader) Decode(decoder *Decoder) error {
-	numFields, err := decoder.StartStruct()
+	header, err := decoder.StartStruct()
 	if err != nil {
 		return err
 	}
+	numFields := header.ElementsOrVersion
 	if numFields < 2 || numFields > 3 {
 		return fmt.Errorf("Invalid message header: it should have 2 or 3 fileds, but has %d", numFields)
 	}
diff --git a/mojo/public/tools/bindings/generators/go_templates/source.tmpl b/mojo/public/tools/bindings/generators/go_templates/source.tmpl
index b697cdf..820f113 100644
--- a/mojo/public/tools/bindings/generators/go_templates/source.tmpl
+++ b/mojo/public/tools/bindings/generators/go_templates/source.tmpl
@@ -11,14 +11,11 @@
 package {{package}}
 
 import (
-	"fmt"
 {% for i in imports %}
 	{{i}}
 {% endfor %}
 )
 
-var _ = fmt.Errorf
-
 {% import "enum.tmpl" as enum_macros %}
 {% import "interface.tmpl" as interface_macros %}
 {% import "struct.tmpl" as struct_macros %}
diff --git a/mojo/public/tools/bindings/generators/go_templates/struct.tmpl b/mojo/public/tools/bindings/generators/go_templates/struct.tmpl
index 457e339..27f91ae 100644
--- a/mojo/public/tools/bindings/generators/go_templates/struct.tmpl
+++ b/mojo/public/tools/bindings/generators/go_templates/struct.tmpl
@@ -23,18 +23,32 @@
 	return nil
 }
 
+var {{struct|name(False)}}_Versions []bindings.DataHeader = []bindings.DataHeader{
+{% for versionInfo in struct.versions %}
+	bindings.DataHeader{{'{'}}{{versionInfo.num_bytes}}, {{versionInfo.version}}{{'}'}},
+{% endfor %}
+}
+
 func (s *{{struct|name(exported)}}) Decode(decoder *bindings.Decoder) error {
-{% if struct.bytes %}
-	version, err := decoder.StartStruct()
-{% else %}
-	_, err := decoder.StartStruct()
-{% endif %}
+	header, err := decoder.StartStruct()
 	if err != nil {
 		return err
 	}
+	index := sort.Search(len({{struct|name(False)}}_Versions), func(i int) bool {
+		return {{struct|name(False)}}_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len({{struct|name(False)}}_Versions) {
+		if {{struct|name(False)}}_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := {{struct|name(False)}}_Versions[index].Size
+		if expectedSize != header.Size {
+			return fmt.Errorf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size)
+		}
+	}
 {% for byte in struct.bytes %}
 {%   for packed_field in byte.packed_fields %}
-	if version >= {{packed_field.min_version}} {
+	if header.ElementsOrVersion >= {{packed_field.min_version}} {
 		{{decode('s.'~packed_field.field|name(exported), packed_field.field.kind)|tab_indent(2)}}
 	}
 {%   endfor %}
diff --git a/mojo/public/tools/bindings/generators/mojom_go_generator.py b/mojo/public/tools/bindings/generators/mojom_go_generator.py
index cb5a16e..536c8ec 100644
--- a/mojo/public/tools/bindings/generators/mojom_go_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_go_generator.py
@@ -259,7 +259,11 @@
         all_structs.append(GetResponseStructFromMethod(method))
 
   if len(all_structs) > 0 or len(module.interfaces) > 0:
+    _imports['fmt'] = 'fmt'
     _imports['mojo/public/go/bindings'] = 'bindings'
+  if len(all_structs) > 0:
+    _imports['sort'] = 'sort'
+
   for struct in all_structs:
     for field in struct.fields:
       AddImport(module, field.kind)