dns/dnsmessage: additional test coverage

Updates golang/go#16218

Change-Id: Ice2821e873807ac4222825f0ca6f47b6a53f90b9
Reviewed-on: https://go-review.googlesource.com/46630
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
diff --git a/dns/dnsmessage/message_test.go b/dns/dnsmessage/message_test.go
index 6c14576..79a811a 100644
--- a/dns/dnsmessage/message_test.go
+++ b/dns/dnsmessage/message_test.go
@@ -159,6 +159,65 @@
 	}
 }
 
+func checkErrorPrefix(err error, prefix string) bool {
+	e, ok := err.(*nestedError)
+	return ok && e.s == prefix
+}
+
+func TestHeaderUnpackError(t *testing.T) {
+	wants := []string{
+		"id",
+		"bits",
+		"questions",
+		"answers",
+		"authorities",
+		"additionals",
+	}
+	var buf []byte
+	var h header
+	for _, want := range wants {
+		n, err := h.unpack(buf, 0)
+		if n != 0 || !checkErrorPrefix(err, want) {
+			t.Errorf("got h.unpack([%d]byte, 0) = %d, %v, want = 0, %s", len(buf), n, err, want)
+		}
+		buf = append(buf, 0, 0)
+	}
+}
+
+func TestParserStart(t *testing.T) {
+	const want = "unpacking header"
+	var p Parser
+	for i := 0; i <= 1; i++ {
+		_, err := p.Start([]byte{})
+		if !checkErrorPrefix(err, want) {
+			t.Errorf("got p.Start(nil) = _, %v, want = _, %s", err, want)
+		}
+	}
+}
+
+func TestResourceNotStarted(t *testing.T) {
+	tests := []struct {
+		name string
+		fn   func(*Parser) error
+	}{
+		{"CNAMEResource", func(p *Parser) error { _, err := p.CNAMEResource(); return err }},
+		{"MXResource", func(p *Parser) error { _, err := p.MXResource(); return err }},
+		{"NSResource", func(p *Parser) error { _, err := p.NSResource(); return err }},
+		{"PTRResource", func(p *Parser) error { _, err := p.PTRResource(); return err }},
+		{"SOAResource", func(p *Parser) error { _, err := p.SOAResource(); return err }},
+		{"TXTResource", func(p *Parser) error { _, err := p.TXTResource(); return err }},
+		{"SRVResource", func(p *Parser) error { _, err := p.SRVResource(); return err }},
+		{"AResource", func(p *Parser) error { _, err := p.AResource(); return err }},
+		{"AAAAResource", func(p *Parser) error { _, err := p.AAAAResource(); return err }},
+	}
+
+	for _, test := range tests {
+		if err := test.fn(&Parser{}); err != ErrNotStarted {
+			t.Errorf("got _, %v = p.%s(), want = _, %v", err, test.name, ErrNotStarted)
+		}
+	}
+}
+
 func TestDNSPackUnpack(t *testing.T) {
 	wants := []Message{
 		{
@@ -410,8 +469,43 @@
 		t.Fatal("b.StartAnswers():", err)
 	}
 	for _, a := range msg.Answers {
-		if err := b.AResource(a.Header, *a.Body.(*AResource)); err != nil {
-			t.Fatalf("b.AResource(%#v): %v", a, err)
+		switch a.Header.Type {
+		case TypeA:
+			if err := b.AResource(a.Header, *a.Body.(*AResource)); err != nil {
+				t.Fatalf("b.AResource(%#v): %v", a, err)
+			}
+		case TypeNS:
+			if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil {
+				t.Fatalf("b.NSResource(%#v): %v", a, err)
+			}
+		case TypeCNAME:
+			if err := b.CNAMEResource(a.Header, *a.Body.(*CNAMEResource)); err != nil {
+				t.Fatalf("b.CNAMEResource(%#v): %v", a, err)
+			}
+		case TypeSOA:
+			if err := b.SOAResource(a.Header, *a.Body.(*SOAResource)); err != nil {
+				t.Fatalf("b.SOAResource(%#v): %v", a, err)
+			}
+		case TypePTR:
+			if err := b.PTRResource(a.Header, *a.Body.(*PTRResource)); err != nil {
+				t.Fatalf("b.PTRResource(%#v): %v", a, err)
+			}
+		case TypeMX:
+			if err := b.MXResource(a.Header, *a.Body.(*MXResource)); err != nil {
+				t.Fatalf("b.MXResource(%#v): %v", a, err)
+			}
+		case TypeTXT:
+			if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil {
+				t.Fatalf("b.TXTResource(%#v): %v", a, err)
+			}
+		case TypeAAAA:
+			if err := b.AAAAResource(a.Header, *a.Body.(*AAAAResource)); err != nil {
+				t.Fatalf("b.AAAAResource(%#v): %v", a, err)
+			}
+		case TypeSRV:
+			if err := b.SRVResource(a.Header, *a.Body.(*SRVResource)); err != nil {
+				t.Fatalf("b.SRVResource(%#v): %v", a, err)
+			}
 		}
 	}
 
@@ -458,7 +552,7 @@
 			},
 		},
 		Answers: []Resource{
-			Resource{
+			{
 				ResourceHeader{
 					Name:  mustNewName("foo.bar.example.com."),
 					Type:  TypeA,
@@ -466,7 +560,7 @@
 				},
 				&AResource{[4]byte{127, 0, 0, 1}},
 			},
-			Resource{
+			{
 				ResourceHeader{
 					Name:  mustNewName("bar.example.com."),
 					Type:  TypeA,
@@ -567,28 +661,28 @@
 			},
 		},
 		Answers: []Resource{
-			Resource{
+			{
 				ResourceHeader{
 					Name:  name,
 					Class: ClassINET,
 				},
 				&AResource{[4]byte{}},
 			},
-			Resource{
+			{
 				ResourceHeader{
 					Name:  name,
 					Class: ClassINET,
 				},
 				&AAAAResource{[16]byte{}},
 			},
-			Resource{
+			{
 				ResourceHeader{
 					Name:  name,
 					Class: ClassINET,
 				},
 				&CNAMEResource{name},
 			},
-			Resource{
+			{
 				ResourceHeader{
 					Name:  name,
 					Class: ClassINET,
@@ -709,45 +803,110 @@
 }
 
 func largeTestMsg() Message {
+	name := mustNewName("foo.bar.example.com.")
 	return Message{
 		Header: Header{Response: true, Authoritative: true},
 		Questions: []Question{
 			{
-				Name:  mustNewName("foo.bar.example.com."),
+				Name:  name,
 				Type:  TypeA,
 				Class: ClassINET,
 			},
 		},
 		Answers: []Resource{
-			Resource{
+			{
 				ResourceHeader{
-					Name:  mustNewName("foo.bar.example.com."),
+					Name:  name,
 					Type:  TypeA,
 					Class: ClassINET,
 				},
 				&AResource{[4]byte{127, 0, 0, 1}},
 			},
-			Resource{
+			{
 				ResourceHeader{
-					Name:  mustNewName("foo.bar.example.com."),
+					Name:  name,
 					Type:  TypeA,
 					Class: ClassINET,
 				},
 				&AResource{[4]byte{127, 0, 0, 2}},
 			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeAAAA,
+					Class: ClassINET,
+				},
+				&AAAAResource{[16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeCNAME,
+					Class: ClassINET,
+				},
+				&CNAMEResource{mustNewName("alias.example.com.")},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeSOA,
+					Class: ClassINET,
+				},
+				&SOAResource{
+					NS:      mustNewName("ns1.example.com."),
+					MBox:    mustNewName("mb.example.com."),
+					Serial:  1,
+					Refresh: 2,
+					Retry:   3,
+					Expire:  4,
+					MinTTL:  5,
+				},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypePTR,
+					Class: ClassINET,
+				},
+				&PTRResource{mustNewName("ptr.example.com.")},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeMX,
+					Class: ClassINET,
+				},
+				&MXResource{
+					7,
+					mustNewName("mx.example.com."),
+				},
+			},
+			{
+				ResourceHeader{
+					Name:  name,
+					Type:  TypeSRV,
+					Class: ClassINET,
+				},
+				&SRVResource{
+					8,
+					9,
+					11,
+					mustNewName("srv.example.com."),
+				},
+			},
 		},
 		Authorities: []Resource{
-			Resource{
+			{
 				ResourceHeader{
-					Name:  mustNewName("foo.bar.example.com."),
+					Name:  name,
 					Type:  TypeNS,
 					Class: ClassINET,
 				},
 				&NSResource{mustNewName("ns1.example.com.")},
 			},
-			Resource{
+			{
 				ResourceHeader{
-					Name:  mustNewName("foo.bar.example.com."),
+					Name:  name,
 					Type:  TypeNS,
 					Class: ClassINET,
 				},
@@ -755,17 +914,17 @@
 			},
 		},
 		Additionals: []Resource{
-			Resource{
+			{
 				ResourceHeader{
-					Name:  mustNewName("foo.bar.example.com."),
+					Name:  name,
 					Type:  TypeTXT,
 					Class: ClassINET,
 				},
 				&TXTResource{"So Long, and Thanks for All the Fish"},
 			},
-			Resource{
+			{
 				ResourceHeader{
-					Name:  mustNewName("foo.bar.example.com."),
+					Name:  name,
 					Type:  TypeTXT,
 					Class: ClassINET,
 				},