github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/http2/frame_test.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package http2
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"reflect"
    12  	"strings"
    13  	"testing"
    14  	"unsafe"
    15  
    16  	"github.com/Andyfoo/golang/x/net/http2/hpack"
    17  )
    18  
    19  func testFramer() (*Framer, *bytes.Buffer) {
    20  	buf := new(bytes.Buffer)
    21  	return NewFramer(buf, buf), buf
    22  }
    23  
    24  func TestFrameSizes(t *testing.T) {
    25  	// Catch people rearranging the FrameHeader fields.
    26  	if got, want := int(unsafe.Sizeof(FrameHeader{})), 12; got != want {
    27  		t.Errorf("FrameHeader size = %d; want %d", got, want)
    28  	}
    29  }
    30  
    31  func TestFrameTypeString(t *testing.T) {
    32  	tests := []struct {
    33  		ft   FrameType
    34  		want string
    35  	}{
    36  		{FrameData, "DATA"},
    37  		{FramePing, "PING"},
    38  		{FrameGoAway, "GOAWAY"},
    39  		{0xf, "UNKNOWN_FRAME_TYPE_15"},
    40  	}
    41  
    42  	for i, tt := range tests {
    43  		got := tt.ft.String()
    44  		if got != tt.want {
    45  			t.Errorf("%d. String(FrameType %d) = %q; want %q", i, int(tt.ft), got, tt.want)
    46  		}
    47  	}
    48  }
    49  
    50  func TestWriteRST(t *testing.T) {
    51  	fr, buf := testFramer()
    52  	var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
    53  	var errCode uint32 = 7<<24 + 6<<16 + 5<<8 + 4
    54  	fr.WriteRSTStream(streamID, ErrCode(errCode))
    55  	const wantEnc = "\x00\x00\x04\x03\x00\x01\x02\x03\x04\x07\x06\x05\x04"
    56  	if buf.String() != wantEnc {
    57  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
    58  	}
    59  	f, err := fr.ReadFrame()
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  	want := &RSTStreamFrame{
    64  		FrameHeader: FrameHeader{
    65  			valid:    true,
    66  			Type:     0x3,
    67  			Flags:    0x0,
    68  			Length:   0x4,
    69  			StreamID: 0x1020304,
    70  		},
    71  		ErrCode: 0x7060504,
    72  	}
    73  	if !reflect.DeepEqual(f, want) {
    74  		t.Errorf("parsed back %#v; want %#v", f, want)
    75  	}
    76  }
    77  
    78  func TestWriteData(t *testing.T) {
    79  	fr, buf := testFramer()
    80  	var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
    81  	data := []byte("ABC")
    82  	fr.WriteData(streamID, true, data)
    83  	const wantEnc = "\x00\x00\x03\x00\x01\x01\x02\x03\x04ABC"
    84  	if buf.String() != wantEnc {
    85  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
    86  	}
    87  	f, err := fr.ReadFrame()
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	df, ok := f.(*DataFrame)
    92  	if !ok {
    93  		t.Fatalf("got %T; want *DataFrame", f)
    94  	}
    95  	if !bytes.Equal(df.Data(), data) {
    96  		t.Errorf("got %q; want %q", df.Data(), data)
    97  	}
    98  	if f.Header().Flags&1 == 0 {
    99  		t.Errorf("didn't see END_STREAM flag")
   100  	}
   101  }
   102  
   103  func TestWriteDataPadded(t *testing.T) {
   104  	tests := [...]struct {
   105  		streamID   uint32
   106  		endStream  bool
   107  		data       []byte
   108  		pad        []byte
   109  		wantHeader FrameHeader
   110  	}{
   111  		// Unpadded:
   112  		0: {
   113  			streamID:  1,
   114  			endStream: true,
   115  			data:      []byte("foo"),
   116  			pad:       nil,
   117  			wantHeader: FrameHeader{
   118  				Type:     FrameData,
   119  				Flags:    FlagDataEndStream,
   120  				Length:   3,
   121  				StreamID: 1,
   122  			},
   123  		},
   124  
   125  		// Padded bit set, but no padding:
   126  		1: {
   127  			streamID:  1,
   128  			endStream: true,
   129  			data:      []byte("foo"),
   130  			pad:       []byte{},
   131  			wantHeader: FrameHeader{
   132  				Type:     FrameData,
   133  				Flags:    FlagDataEndStream | FlagDataPadded,
   134  				Length:   4,
   135  				StreamID: 1,
   136  			},
   137  		},
   138  
   139  		// Padded bit set, with padding:
   140  		2: {
   141  			streamID:  1,
   142  			endStream: false,
   143  			data:      []byte("foo"),
   144  			pad:       []byte{0, 0, 0},
   145  			wantHeader: FrameHeader{
   146  				Type:     FrameData,
   147  				Flags:    FlagDataPadded,
   148  				Length:   7,
   149  				StreamID: 1,
   150  			},
   151  		},
   152  	}
   153  	for i, tt := range tests {
   154  		fr, _ := testFramer()
   155  		fr.WriteDataPadded(tt.streamID, tt.endStream, tt.data, tt.pad)
   156  		f, err := fr.ReadFrame()
   157  		if err != nil {
   158  			t.Errorf("%d. ReadFrame: %v", i, err)
   159  			continue
   160  		}
   161  		got := f.Header()
   162  		tt.wantHeader.valid = true
   163  		if got != tt.wantHeader {
   164  			t.Errorf("%d. read %+v; want %+v", i, got, tt.wantHeader)
   165  			continue
   166  		}
   167  		df := f.(*DataFrame)
   168  		if !bytes.Equal(df.Data(), tt.data) {
   169  			t.Errorf("%d. got %q; want %q", i, df.Data(), tt.data)
   170  		}
   171  	}
   172  }
   173  
   174  func TestWriteHeaders(t *testing.T) {
   175  	tests := []struct {
   176  		name      string
   177  		p         HeadersFrameParam
   178  		wantEnc   string
   179  		wantFrame *HeadersFrame
   180  	}{
   181  		{
   182  			"basic",
   183  			HeadersFrameParam{
   184  				StreamID:      42,
   185  				BlockFragment: []byte("abc"),
   186  				Priority:      PriorityParam{},
   187  			},
   188  			"\x00\x00\x03\x01\x00\x00\x00\x00*abc",
   189  			&HeadersFrame{
   190  				FrameHeader: FrameHeader{
   191  					valid:    true,
   192  					StreamID: 42,
   193  					Type:     FrameHeaders,
   194  					Length:   uint32(len("abc")),
   195  				},
   196  				Priority:      PriorityParam{},
   197  				headerFragBuf: []byte("abc"),
   198  			},
   199  		},
   200  		{
   201  			"basic + end flags",
   202  			HeadersFrameParam{
   203  				StreamID:      42,
   204  				BlockFragment: []byte("abc"),
   205  				EndStream:     true,
   206  				EndHeaders:    true,
   207  				Priority:      PriorityParam{},
   208  			},
   209  			"\x00\x00\x03\x01\x05\x00\x00\x00*abc",
   210  			&HeadersFrame{
   211  				FrameHeader: FrameHeader{
   212  					valid:    true,
   213  					StreamID: 42,
   214  					Type:     FrameHeaders,
   215  					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders,
   216  					Length:   uint32(len("abc")),
   217  				},
   218  				Priority:      PriorityParam{},
   219  				headerFragBuf: []byte("abc"),
   220  			},
   221  		},
   222  		{
   223  			"with padding",
   224  			HeadersFrameParam{
   225  				StreamID:      42,
   226  				BlockFragment: []byte("abc"),
   227  				EndStream:     true,
   228  				EndHeaders:    true,
   229  				PadLength:     5,
   230  				Priority:      PriorityParam{},
   231  			},
   232  			"\x00\x00\t\x01\r\x00\x00\x00*\x05abc\x00\x00\x00\x00\x00",
   233  			&HeadersFrame{
   234  				FrameHeader: FrameHeader{
   235  					valid:    true,
   236  					StreamID: 42,
   237  					Type:     FrameHeaders,
   238  					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded,
   239  					Length:   uint32(1 + len("abc") + 5), // pad length + contents + padding
   240  				},
   241  				Priority:      PriorityParam{},
   242  				headerFragBuf: []byte("abc"),
   243  			},
   244  		},
   245  		{
   246  			"with priority",
   247  			HeadersFrameParam{
   248  				StreamID:      42,
   249  				BlockFragment: []byte("abc"),
   250  				EndStream:     true,
   251  				EndHeaders:    true,
   252  				PadLength:     2,
   253  				Priority: PriorityParam{
   254  					StreamDep: 15,
   255  					Exclusive: true,
   256  					Weight:    127,
   257  				},
   258  			},
   259  			"\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x0f\u007fabc\x00\x00",
   260  			&HeadersFrame{
   261  				FrameHeader: FrameHeader{
   262  					valid:    true,
   263  					StreamID: 42,
   264  					Type:     FrameHeaders,
   265  					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority,
   266  					Length:   uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding
   267  				},
   268  				Priority: PriorityParam{
   269  					StreamDep: 15,
   270  					Exclusive: true,
   271  					Weight:    127,
   272  				},
   273  				headerFragBuf: []byte("abc"),
   274  			},
   275  		},
   276  		{
   277  			"with priority stream dep zero", // golang.org/issue/15444
   278  			HeadersFrameParam{
   279  				StreamID:      42,
   280  				BlockFragment: []byte("abc"),
   281  				EndStream:     true,
   282  				EndHeaders:    true,
   283  				PadLength:     2,
   284  				Priority: PriorityParam{
   285  					StreamDep: 0,
   286  					Exclusive: true,
   287  					Weight:    127,
   288  				},
   289  			},
   290  			"\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x00\u007fabc\x00\x00",
   291  			&HeadersFrame{
   292  				FrameHeader: FrameHeader{
   293  					valid:    true,
   294  					StreamID: 42,
   295  					Type:     FrameHeaders,
   296  					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority,
   297  					Length:   uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding
   298  				},
   299  				Priority: PriorityParam{
   300  					StreamDep: 0,
   301  					Exclusive: true,
   302  					Weight:    127,
   303  				},
   304  				headerFragBuf: []byte("abc"),
   305  			},
   306  		},
   307  	}
   308  	for _, tt := range tests {
   309  		fr, buf := testFramer()
   310  		if err := fr.WriteHeaders(tt.p); err != nil {
   311  			t.Errorf("test %q: %v", tt.name, err)
   312  			continue
   313  		}
   314  		if buf.String() != tt.wantEnc {
   315  			t.Errorf("test %q: encoded %q; want %q", tt.name, buf.Bytes(), tt.wantEnc)
   316  		}
   317  		f, err := fr.ReadFrame()
   318  		if err != nil {
   319  			t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
   320  			continue
   321  		}
   322  		if !reflect.DeepEqual(f, tt.wantFrame) {
   323  			t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
   324  		}
   325  	}
   326  }
   327  
   328  func TestWriteInvalidStreamDep(t *testing.T) {
   329  	fr, _ := testFramer()
   330  	err := fr.WriteHeaders(HeadersFrameParam{
   331  		StreamID: 42,
   332  		Priority: PriorityParam{
   333  			StreamDep: 1 << 31,
   334  		},
   335  	})
   336  	if err != errDepStreamID {
   337  		t.Errorf("header error = %v; want %q", err, errDepStreamID)
   338  	}
   339  
   340  	err = fr.WritePriority(2, PriorityParam{StreamDep: 1 << 31})
   341  	if err != errDepStreamID {
   342  		t.Errorf("priority error = %v; want %q", err, errDepStreamID)
   343  	}
   344  }
   345  
   346  func TestWriteContinuation(t *testing.T) {
   347  	const streamID = 42
   348  	tests := []struct {
   349  		name string
   350  		end  bool
   351  		frag []byte
   352  
   353  		wantFrame *ContinuationFrame
   354  	}{
   355  		{
   356  			"not end",
   357  			false,
   358  			[]byte("abc"),
   359  			&ContinuationFrame{
   360  				FrameHeader: FrameHeader{
   361  					valid:    true,
   362  					StreamID: streamID,
   363  					Type:     FrameContinuation,
   364  					Length:   uint32(len("abc")),
   365  				},
   366  				headerFragBuf: []byte("abc"),
   367  			},
   368  		},
   369  		{
   370  			"end",
   371  			true,
   372  			[]byte("def"),
   373  			&ContinuationFrame{
   374  				FrameHeader: FrameHeader{
   375  					valid:    true,
   376  					StreamID: streamID,
   377  					Type:     FrameContinuation,
   378  					Flags:    FlagContinuationEndHeaders,
   379  					Length:   uint32(len("def")),
   380  				},
   381  				headerFragBuf: []byte("def"),
   382  			},
   383  		},
   384  	}
   385  	for _, tt := range tests {
   386  		fr, _ := testFramer()
   387  		if err := fr.WriteContinuation(streamID, tt.end, tt.frag); err != nil {
   388  			t.Errorf("test %q: %v", tt.name, err)
   389  			continue
   390  		}
   391  		fr.AllowIllegalReads = true
   392  		f, err := fr.ReadFrame()
   393  		if err != nil {
   394  			t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
   395  			continue
   396  		}
   397  		if !reflect.DeepEqual(f, tt.wantFrame) {
   398  			t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
   399  		}
   400  	}
   401  }
   402  
   403  func TestWritePriority(t *testing.T) {
   404  	const streamID = 42
   405  	tests := []struct {
   406  		name      string
   407  		priority  PriorityParam
   408  		wantFrame *PriorityFrame
   409  	}{
   410  		{
   411  			"not exclusive",
   412  			PriorityParam{
   413  				StreamDep: 2,
   414  				Exclusive: false,
   415  				Weight:    127,
   416  			},
   417  			&PriorityFrame{
   418  				FrameHeader{
   419  					valid:    true,
   420  					StreamID: streamID,
   421  					Type:     FramePriority,
   422  					Length:   5,
   423  				},
   424  				PriorityParam{
   425  					StreamDep: 2,
   426  					Exclusive: false,
   427  					Weight:    127,
   428  				},
   429  			},
   430  		},
   431  
   432  		{
   433  			"exclusive",
   434  			PriorityParam{
   435  				StreamDep: 3,
   436  				Exclusive: true,
   437  				Weight:    77,
   438  			},
   439  			&PriorityFrame{
   440  				FrameHeader{
   441  					valid:    true,
   442  					StreamID: streamID,
   443  					Type:     FramePriority,
   444  					Length:   5,
   445  				},
   446  				PriorityParam{
   447  					StreamDep: 3,
   448  					Exclusive: true,
   449  					Weight:    77,
   450  				},
   451  			},
   452  		},
   453  	}
   454  	for _, tt := range tests {
   455  		fr, _ := testFramer()
   456  		if err := fr.WritePriority(streamID, tt.priority); err != nil {
   457  			t.Errorf("test %q: %v", tt.name, err)
   458  			continue
   459  		}
   460  		f, err := fr.ReadFrame()
   461  		if err != nil {
   462  			t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
   463  			continue
   464  		}
   465  		if !reflect.DeepEqual(f, tt.wantFrame) {
   466  			t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
   467  		}
   468  	}
   469  }
   470  
   471  func TestWriteSettings(t *testing.T) {
   472  	fr, buf := testFramer()
   473  	settings := []Setting{{1, 2}, {3, 4}}
   474  	fr.WriteSettings(settings...)
   475  	const wantEnc = "\x00\x00\f\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00\x04"
   476  	if buf.String() != wantEnc {
   477  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   478  	}
   479  	f, err := fr.ReadFrame()
   480  	if err != nil {
   481  		t.Fatal(err)
   482  	}
   483  	sf, ok := f.(*SettingsFrame)
   484  	if !ok {
   485  		t.Fatalf("Got a %T; want a SettingsFrame", f)
   486  	}
   487  	var got []Setting
   488  	sf.ForeachSetting(func(s Setting) error {
   489  		got = append(got, s)
   490  		valBack, ok := sf.Value(s.ID)
   491  		if !ok || valBack != s.Val {
   492  			t.Errorf("Value(%d) = %v, %v; want %v, true", s.ID, valBack, ok, s.Val)
   493  		}
   494  		return nil
   495  	})
   496  	if !reflect.DeepEqual(settings, got) {
   497  		t.Errorf("Read settings %+v != written settings %+v", got, settings)
   498  	}
   499  }
   500  
   501  func TestWriteSettingsAck(t *testing.T) {
   502  	fr, buf := testFramer()
   503  	fr.WriteSettingsAck()
   504  	const wantEnc = "\x00\x00\x00\x04\x01\x00\x00\x00\x00"
   505  	if buf.String() != wantEnc {
   506  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   507  	}
   508  }
   509  
   510  func TestWriteWindowUpdate(t *testing.T) {
   511  	fr, buf := testFramer()
   512  	const streamID = 1<<24 + 2<<16 + 3<<8 + 4
   513  	const incr = 7<<24 + 6<<16 + 5<<8 + 4
   514  	if err := fr.WriteWindowUpdate(streamID, incr); err != nil {
   515  		t.Fatal(err)
   516  	}
   517  	const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04"
   518  	if buf.String() != wantEnc {
   519  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   520  	}
   521  	f, err := fr.ReadFrame()
   522  	if err != nil {
   523  		t.Fatal(err)
   524  	}
   525  	want := &WindowUpdateFrame{
   526  		FrameHeader: FrameHeader{
   527  			valid:    true,
   528  			Type:     0x8,
   529  			Flags:    0x0,
   530  			Length:   0x4,
   531  			StreamID: 0x1020304,
   532  		},
   533  		Increment: 0x7060504,
   534  	}
   535  	if !reflect.DeepEqual(f, want) {
   536  		t.Errorf("parsed back %#v; want %#v", f, want)
   537  	}
   538  }
   539  
   540  func TestWritePing(t *testing.T)    { testWritePing(t, false) }
   541  func TestWritePingAck(t *testing.T) { testWritePing(t, true) }
   542  
   543  func testWritePing(t *testing.T, ack bool) {
   544  	fr, buf := testFramer()
   545  	if err := fr.WritePing(ack, [8]byte{1, 2, 3, 4, 5, 6, 7, 8}); err != nil {
   546  		t.Fatal(err)
   547  	}
   548  	var wantFlags Flags
   549  	if ack {
   550  		wantFlags = FlagPingAck
   551  	}
   552  	var wantEnc = "\x00\x00\x08\x06" + string(wantFlags) + "\x00\x00\x00\x00" + "\x01\x02\x03\x04\x05\x06\x07\x08"
   553  	if buf.String() != wantEnc {
   554  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   555  	}
   556  
   557  	f, err := fr.ReadFrame()
   558  	if err != nil {
   559  		t.Fatal(err)
   560  	}
   561  	want := &PingFrame{
   562  		FrameHeader: FrameHeader{
   563  			valid:    true,
   564  			Type:     0x6,
   565  			Flags:    wantFlags,
   566  			Length:   0x8,
   567  			StreamID: 0,
   568  		},
   569  		Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
   570  	}
   571  	if !reflect.DeepEqual(f, want) {
   572  		t.Errorf("parsed back %#v; want %#v", f, want)
   573  	}
   574  }
   575  
   576  func TestReadFrameHeader(t *testing.T) {
   577  	tests := []struct {
   578  		in   string
   579  		want FrameHeader
   580  	}{
   581  		{in: "\x00\x00\x00" + "\x00" + "\x00" + "\x00\x00\x00\x00", want: FrameHeader{}},
   582  		{in: "\x01\x02\x03" + "\x04" + "\x05" + "\x06\x07\x08\x09", want: FrameHeader{
   583  			Length: 66051, Type: 4, Flags: 5, StreamID: 101124105,
   584  		}},
   585  		// Ignore high bit:
   586  		{in: "\xff\xff\xff" + "\xff" + "\xff" + "\xff\xff\xff\xff", want: FrameHeader{
   587  			Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
   588  		{in: "\xff\xff\xff" + "\xff" + "\xff" + "\x7f\xff\xff\xff", want: FrameHeader{
   589  			Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
   590  	}
   591  	for i, tt := range tests {
   592  		got, err := readFrameHeader(make([]byte, 9), strings.NewReader(tt.in))
   593  		if err != nil {
   594  			t.Errorf("%d. readFrameHeader(%q) = %v", i, tt.in, err)
   595  			continue
   596  		}
   597  		tt.want.valid = true
   598  		if got != tt.want {
   599  			t.Errorf("%d. readFrameHeader(%q) = %+v; want %+v", i, tt.in, got, tt.want)
   600  		}
   601  	}
   602  }
   603  
   604  func TestReadWriteFrameHeader(t *testing.T) {
   605  	tests := []struct {
   606  		len      uint32
   607  		typ      FrameType
   608  		flags    Flags
   609  		streamID uint32
   610  	}{
   611  		{len: 0, typ: 255, flags: 1, streamID: 0},
   612  		{len: 0, typ: 255, flags: 1, streamID: 1},
   613  		{len: 0, typ: 255, flags: 1, streamID: 255},
   614  		{len: 0, typ: 255, flags: 1, streamID: 256},
   615  		{len: 0, typ: 255, flags: 1, streamID: 65535},
   616  		{len: 0, typ: 255, flags: 1, streamID: 65536},
   617  
   618  		{len: 0, typ: 1, flags: 255, streamID: 1},
   619  		{len: 255, typ: 1, flags: 255, streamID: 1},
   620  		{len: 256, typ: 1, flags: 255, streamID: 1},
   621  		{len: 65535, typ: 1, flags: 255, streamID: 1},
   622  		{len: 65536, typ: 1, flags: 255, streamID: 1},
   623  		{len: 16777215, typ: 1, flags: 255, streamID: 1},
   624  	}
   625  	for _, tt := range tests {
   626  		fr, buf := testFramer()
   627  		fr.startWrite(tt.typ, tt.flags, tt.streamID)
   628  		fr.writeBytes(make([]byte, tt.len))
   629  		fr.endWrite()
   630  		fh, err := ReadFrameHeader(buf)
   631  		if err != nil {
   632  			t.Errorf("ReadFrameHeader(%+v) = %v", tt, err)
   633  			continue
   634  		}
   635  		if fh.Type != tt.typ || fh.Flags != tt.flags || fh.Length != tt.len || fh.StreamID != tt.streamID {
   636  			t.Errorf("ReadFrameHeader(%+v) = %+v; mismatch", tt, fh)
   637  		}
   638  	}
   639  
   640  }
   641  
   642  func TestWriteTooLargeFrame(t *testing.T) {
   643  	fr, _ := testFramer()
   644  	fr.startWrite(0, 1, 1)
   645  	fr.writeBytes(make([]byte, 1<<24))
   646  	err := fr.endWrite()
   647  	if err != ErrFrameTooLarge {
   648  		t.Errorf("endWrite = %v; want errFrameTooLarge", err)
   649  	}
   650  }
   651  
   652  func TestWriteGoAway(t *testing.T) {
   653  	const debug = "foo"
   654  	fr, buf := testFramer()
   655  	if err := fr.WriteGoAway(0x01020304, 0x05060708, []byte(debug)); err != nil {
   656  		t.Fatal(err)
   657  	}
   658  	const wantEnc = "\x00\x00\v\a\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + debug
   659  	if buf.String() != wantEnc {
   660  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   661  	}
   662  	f, err := fr.ReadFrame()
   663  	if err != nil {
   664  		t.Fatal(err)
   665  	}
   666  	want := &GoAwayFrame{
   667  		FrameHeader: FrameHeader{
   668  			valid:    true,
   669  			Type:     0x7,
   670  			Flags:    0,
   671  			Length:   uint32(4 + 4 + len(debug)),
   672  			StreamID: 0,
   673  		},
   674  		LastStreamID: 0x01020304,
   675  		ErrCode:      0x05060708,
   676  		debugData:    []byte(debug),
   677  	}
   678  	if !reflect.DeepEqual(f, want) {
   679  		t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
   680  	}
   681  	if got := string(f.(*GoAwayFrame).DebugData()); got != debug {
   682  		t.Errorf("debug data = %q; want %q", got, debug)
   683  	}
   684  }
   685  
   686  func TestWritePushPromise(t *testing.T) {
   687  	pp := PushPromiseParam{
   688  		StreamID:      42,
   689  		PromiseID:     42,
   690  		BlockFragment: []byte("abc"),
   691  	}
   692  	fr, buf := testFramer()
   693  	if err := fr.WritePushPromise(pp); err != nil {
   694  		t.Fatal(err)
   695  	}
   696  	const wantEnc = "\x00\x00\x07\x05\x00\x00\x00\x00*\x00\x00\x00*abc"
   697  	if buf.String() != wantEnc {
   698  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   699  	}
   700  	f, err := fr.ReadFrame()
   701  	if err != nil {
   702  		t.Fatal(err)
   703  	}
   704  	_, ok := f.(*PushPromiseFrame)
   705  	if !ok {
   706  		t.Fatalf("got %T; want *PushPromiseFrame", f)
   707  	}
   708  	want := &PushPromiseFrame{
   709  		FrameHeader: FrameHeader{
   710  			valid:    true,
   711  			Type:     0x5,
   712  			Flags:    0x0,
   713  			Length:   0x7,
   714  			StreamID: 42,
   715  		},
   716  		PromiseID:     42,
   717  		headerFragBuf: []byte("abc"),
   718  	}
   719  	if !reflect.DeepEqual(f, want) {
   720  		t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
   721  	}
   722  }
   723  
   724  // test checkFrameOrder and that HEADERS and CONTINUATION frames can't be intermingled.
   725  func TestReadFrameOrder(t *testing.T) {
   726  	head := func(f *Framer, id uint32, end bool) {
   727  		f.WriteHeaders(HeadersFrameParam{
   728  			StreamID:      id,
   729  			BlockFragment: []byte("foo"), // unused, but non-empty
   730  			EndHeaders:    end,
   731  		})
   732  	}
   733  	cont := func(f *Framer, id uint32, end bool) {
   734  		f.WriteContinuation(id, end, []byte("foo"))
   735  	}
   736  
   737  	tests := [...]struct {
   738  		name    string
   739  		w       func(*Framer)
   740  		atLeast int
   741  		wantErr string
   742  	}{
   743  		0: {
   744  			w: func(f *Framer) {
   745  				head(f, 1, true)
   746  			},
   747  		},
   748  		1: {
   749  			w: func(f *Framer) {
   750  				head(f, 1, true)
   751  				head(f, 2, true)
   752  			},
   753  		},
   754  		2: {
   755  			wantErr: "got HEADERS for stream 2; expected CONTINUATION following HEADERS for stream 1",
   756  			w: func(f *Framer) {
   757  				head(f, 1, false)
   758  				head(f, 2, true)
   759  			},
   760  		},
   761  		3: {
   762  			wantErr: "got DATA for stream 1; expected CONTINUATION following HEADERS for stream 1",
   763  			w: func(f *Framer) {
   764  				head(f, 1, false)
   765  			},
   766  		},
   767  		4: {
   768  			w: func(f *Framer) {
   769  				head(f, 1, false)
   770  				cont(f, 1, true)
   771  				head(f, 2, true)
   772  			},
   773  		},
   774  		5: {
   775  			wantErr: "got CONTINUATION for stream 2; expected stream 1",
   776  			w: func(f *Framer) {
   777  				head(f, 1, false)
   778  				cont(f, 2, true)
   779  				head(f, 2, true)
   780  			},
   781  		},
   782  		6: {
   783  			wantErr: "unexpected CONTINUATION for stream 1",
   784  			w: func(f *Framer) {
   785  				cont(f, 1, true)
   786  			},
   787  		},
   788  		7: {
   789  			wantErr: "unexpected CONTINUATION for stream 1",
   790  			w: func(f *Framer) {
   791  				cont(f, 1, false)
   792  			},
   793  		},
   794  		8: {
   795  			wantErr: "HEADERS frame with stream ID 0",
   796  			w: func(f *Framer) {
   797  				head(f, 0, true)
   798  			},
   799  		},
   800  		9: {
   801  			wantErr: "CONTINUATION frame with stream ID 0",
   802  			w: func(f *Framer) {
   803  				cont(f, 0, true)
   804  			},
   805  		},
   806  		10: {
   807  			wantErr: "unexpected CONTINUATION for stream 1",
   808  			atLeast: 5,
   809  			w: func(f *Framer) {
   810  				head(f, 1, false)
   811  				cont(f, 1, false)
   812  				cont(f, 1, false)
   813  				cont(f, 1, false)
   814  				cont(f, 1, true)
   815  				cont(f, 1, false)
   816  			},
   817  		},
   818  	}
   819  	for i, tt := range tests {
   820  		buf := new(bytes.Buffer)
   821  		f := NewFramer(buf, buf)
   822  		f.AllowIllegalWrites = true
   823  		tt.w(f)
   824  		f.WriteData(1, true, nil) // to test transition away from last step
   825  
   826  		var err error
   827  		n := 0
   828  		var log bytes.Buffer
   829  		for {
   830  			var got Frame
   831  			got, err = f.ReadFrame()
   832  			fmt.Fprintf(&log, "  read %v, %v\n", got, err)
   833  			if err != nil {
   834  				break
   835  			}
   836  			n++
   837  		}
   838  		if err == io.EOF {
   839  			err = nil
   840  		}
   841  		ok := tt.wantErr == ""
   842  		if ok && err != nil {
   843  			t.Errorf("%d. after %d good frames, ReadFrame = %v; want success\n%s", i, n, err, log.Bytes())
   844  			continue
   845  		}
   846  		if !ok && err != ConnectionError(ErrCodeProtocol) {
   847  			t.Errorf("%d. after %d good frames, ReadFrame = %v; want ConnectionError(ErrCodeProtocol)\n%s", i, n, err, log.Bytes())
   848  			continue
   849  		}
   850  		if !((f.errDetail == nil && tt.wantErr == "") || (fmt.Sprint(f.errDetail) == tt.wantErr)) {
   851  			t.Errorf("%d. framer eror = %q; want %q\n%s", i, f.errDetail, tt.wantErr, log.Bytes())
   852  		}
   853  		if n < tt.atLeast {
   854  			t.Errorf("%d. framer only read %d frames; want at least %d\n%s", i, n, tt.atLeast, log.Bytes())
   855  		}
   856  	}
   857  }
   858  
   859  func TestMetaFrameHeader(t *testing.T) {
   860  	write := func(f *Framer, frags ...[]byte) {
   861  		for i, frag := range frags {
   862  			end := (i == len(frags)-1)
   863  			if i == 0 {
   864  				f.WriteHeaders(HeadersFrameParam{
   865  					StreamID:      1,
   866  					BlockFragment: frag,
   867  					EndHeaders:    end,
   868  				})
   869  			} else {
   870  				f.WriteContinuation(1, end, frag)
   871  			}
   872  		}
   873  	}
   874  
   875  	want := func(flags Flags, length uint32, pairs ...string) *MetaHeadersFrame {
   876  		mh := &MetaHeadersFrame{
   877  			HeadersFrame: &HeadersFrame{
   878  				FrameHeader: FrameHeader{
   879  					Type:     FrameHeaders,
   880  					Flags:    flags,
   881  					Length:   length,
   882  					StreamID: 1,
   883  				},
   884  			},
   885  			Fields: []hpack.HeaderField(nil),
   886  		}
   887  		for len(pairs) > 0 {
   888  			mh.Fields = append(mh.Fields, hpack.HeaderField{
   889  				Name:  pairs[0],
   890  				Value: pairs[1],
   891  			})
   892  			pairs = pairs[2:]
   893  		}
   894  		return mh
   895  	}
   896  	truncated := func(mh *MetaHeadersFrame) *MetaHeadersFrame {
   897  		mh.Truncated = true
   898  		return mh
   899  	}
   900  
   901  	const noFlags Flags = 0
   902  
   903  	oneKBString := strings.Repeat("a", 1<<10)
   904  
   905  	tests := [...]struct {
   906  		name              string
   907  		w                 func(*Framer)
   908  		want              interface{} // *MetaHeaderFrame or error
   909  		wantErrReason     string
   910  		maxHeaderListSize uint32
   911  	}{
   912  		0: {
   913  			name: "single_headers",
   914  			w: func(f *Framer) {
   915  				var he hpackEncoder
   916  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/")
   917  				write(f, all)
   918  			},
   919  			want: want(FlagHeadersEndHeaders, 2, ":method", "GET", ":path", "/"),
   920  		},
   921  		1: {
   922  			name: "with_continuation",
   923  			w: func(f *Framer) {
   924  				var he hpackEncoder
   925  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar")
   926  				write(f, all[:1], all[1:])
   927  			},
   928  			want: want(noFlags, 1, ":method", "GET", ":path", "/", "foo", "bar"),
   929  		},
   930  		2: {
   931  			name: "with_two_continuation",
   932  			w: func(f *Framer) {
   933  				var he hpackEncoder
   934  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar")
   935  				write(f, all[:2], all[2:4], all[4:])
   936  			},
   937  			want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", "bar"),
   938  		},
   939  		3: {
   940  			name: "big_string_okay",
   941  			w: func(f *Framer) {
   942  				var he hpackEncoder
   943  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString)
   944  				write(f, all[:2], all[2:])
   945  			},
   946  			want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", oneKBString),
   947  		},
   948  		4: {
   949  			name: "big_string_error",
   950  			w: func(f *Framer) {
   951  				var he hpackEncoder
   952  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString)
   953  				write(f, all[:2], all[2:])
   954  			},
   955  			maxHeaderListSize: (1 << 10) / 2,
   956  			want:              ConnectionError(ErrCodeCompression),
   957  		},
   958  		5: {
   959  			name: "max_header_list_truncated",
   960  			w: func(f *Framer) {
   961  				var he hpackEncoder
   962  				var pairs = []string{":method", "GET", ":path", "/"}
   963  				for i := 0; i < 100; i++ {
   964  					pairs = append(pairs, "foo", "bar")
   965  				}
   966  				all := he.encodeHeaderRaw(t, pairs...)
   967  				write(f, all[:2], all[2:])
   968  			},
   969  			maxHeaderListSize: (1 << 10) / 2,
   970  			want: truncated(want(noFlags, 2,
   971  				":method", "GET",
   972  				":path", "/",
   973  				"foo", "bar",
   974  				"foo", "bar",
   975  				"foo", "bar",
   976  				"foo", "bar",
   977  				"foo", "bar",
   978  				"foo", "bar",
   979  				"foo", "bar",
   980  				"foo", "bar",
   981  				"foo", "bar",
   982  				"foo", "bar",
   983  				"foo", "bar", // 11
   984  			)),
   985  		},
   986  		6: {
   987  			name: "pseudo_order",
   988  			w: func(f *Framer) {
   989  				write(f, encodeHeaderRaw(t,
   990  					":method", "GET",
   991  					"foo", "bar",
   992  					":path", "/", // bogus
   993  				))
   994  			},
   995  			want:          streamError(1, ErrCodeProtocol),
   996  			wantErrReason: "pseudo header field after regular",
   997  		},
   998  		7: {
   999  			name: "pseudo_unknown",
  1000  			w: func(f *Framer) {
  1001  				write(f, encodeHeaderRaw(t,
  1002  					":unknown", "foo", // bogus
  1003  					"foo", "bar",
  1004  				))
  1005  			},
  1006  			want:          streamError(1, ErrCodeProtocol),
  1007  			wantErrReason: "invalid pseudo-header \":unknown\"",
  1008  		},
  1009  		8: {
  1010  			name: "pseudo_mix_request_response",
  1011  			w: func(f *Framer) {
  1012  				write(f, encodeHeaderRaw(t,
  1013  					":method", "GET",
  1014  					":status", "100",
  1015  				))
  1016  			},
  1017  			want:          streamError(1, ErrCodeProtocol),
  1018  			wantErrReason: "mix of request and response pseudo headers",
  1019  		},
  1020  		9: {
  1021  			name: "pseudo_dup",
  1022  			w: func(f *Framer) {
  1023  				write(f, encodeHeaderRaw(t,
  1024  					":method", "GET",
  1025  					":method", "POST",
  1026  				))
  1027  			},
  1028  			want:          streamError(1, ErrCodeProtocol),
  1029  			wantErrReason: "duplicate pseudo-header \":method\"",
  1030  		},
  1031  		10: {
  1032  			name: "trailer_okay_no_pseudo",
  1033  			w:    func(f *Framer) { write(f, encodeHeaderRaw(t, "foo", "bar")) },
  1034  			want: want(FlagHeadersEndHeaders, 8, "foo", "bar"),
  1035  		},
  1036  		11: {
  1037  			name:          "invalid_field_name",
  1038  			w:             func(f *Framer) { write(f, encodeHeaderRaw(t, "CapitalBad", "x")) },
  1039  			want:          streamError(1, ErrCodeProtocol),
  1040  			wantErrReason: "invalid header field name \"CapitalBad\"",
  1041  		},
  1042  		12: {
  1043  			name:          "invalid_field_value",
  1044  			w:             func(f *Framer) { write(f, encodeHeaderRaw(t, "key", "bad_null\x00")) },
  1045  			want:          streamError(1, ErrCodeProtocol),
  1046  			wantErrReason: "invalid header field value \"bad_null\\x00\"",
  1047  		},
  1048  	}
  1049  	for i, tt := range tests {
  1050  		buf := new(bytes.Buffer)
  1051  		f := NewFramer(buf, buf)
  1052  		f.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
  1053  		f.MaxHeaderListSize = tt.maxHeaderListSize
  1054  		tt.w(f)
  1055  
  1056  		name := tt.name
  1057  		if name == "" {
  1058  			name = fmt.Sprintf("test index %d", i)
  1059  		}
  1060  
  1061  		var got interface{}
  1062  		var err error
  1063  		got, err = f.ReadFrame()
  1064  		if err != nil {
  1065  			got = err
  1066  
  1067  			// Ignore the StreamError.Cause field, if it matches the wantErrReason.
  1068  			// The test table above predates the Cause field.
  1069  			if se, ok := err.(StreamError); ok && se.Cause != nil && se.Cause.Error() == tt.wantErrReason {
  1070  				se.Cause = nil
  1071  				got = se
  1072  			}
  1073  		}
  1074  		if !reflect.DeepEqual(got, tt.want) {
  1075  			if mhg, ok := got.(*MetaHeadersFrame); ok {
  1076  				if mhw, ok := tt.want.(*MetaHeadersFrame); ok {
  1077  					hg := mhg.HeadersFrame
  1078  					hw := mhw.HeadersFrame
  1079  					if hg != nil && hw != nil && !reflect.DeepEqual(*hg, *hw) {
  1080  						t.Errorf("%s: headers differ:\n got: %+v\nwant: %+v\n", name, *hg, *hw)
  1081  					}
  1082  				}
  1083  			}
  1084  			str := func(v interface{}) string {
  1085  				if _, ok := v.(error); ok {
  1086  					return fmt.Sprintf("error %v", v)
  1087  				} else {
  1088  					return fmt.Sprintf("value %#v", v)
  1089  				}
  1090  			}
  1091  			t.Errorf("%s:\n got: %v\nwant: %s", name, str(got), str(tt.want))
  1092  		}
  1093  		if tt.wantErrReason != "" && tt.wantErrReason != fmt.Sprint(f.errDetail) {
  1094  			t.Errorf("%s: got error reason %q; want %q", name, f.errDetail, tt.wantErrReason)
  1095  		}
  1096  	}
  1097  }
  1098  
  1099  func TestSetReuseFrames(t *testing.T) {
  1100  	fr, buf := testFramer()
  1101  	fr.SetReuseFrames()
  1102  
  1103  	// Check that DataFrames are reused. Note that
  1104  	// SetReuseFrames only currently implements reuse of DataFrames.
  1105  	firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t)
  1106  
  1107  	for i := 0; i < 10; i++ {
  1108  		df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
  1109  		if df != firstDf {
  1110  			t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
  1111  		}
  1112  	}
  1113  
  1114  	for i := 0; i < 10; i++ {
  1115  		df := readAndVerifyDataFrame("", 0, fr, buf, t)
  1116  		if df != firstDf {
  1117  			t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
  1118  		}
  1119  	}
  1120  
  1121  	for i := 0; i < 10; i++ {
  1122  		df := readAndVerifyDataFrame("HHH", 3, fr, buf, t)
  1123  		if df != firstDf {
  1124  			t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
  1125  		}
  1126  	}
  1127  }
  1128  
  1129  func TestSetReuseFramesMoreThanOnce(t *testing.T) {
  1130  	fr, buf := testFramer()
  1131  	fr.SetReuseFrames()
  1132  
  1133  	firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t)
  1134  	fr.SetReuseFrames()
  1135  
  1136  	for i := 0; i < 10; i++ {
  1137  		df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
  1138  		// SetReuseFrames should be idempotent
  1139  		fr.SetReuseFrames()
  1140  		if df != firstDf {
  1141  			t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
  1142  		}
  1143  	}
  1144  }
  1145  
  1146  func TestNoSetReuseFrames(t *testing.T) {
  1147  	fr, buf := testFramer()
  1148  	const numNewDataFrames = 10
  1149  	dfSoFar := make([]interface{}, numNewDataFrames)
  1150  
  1151  	// Check that DataFrames are not reused if SetReuseFrames wasn't called.
  1152  	// SetReuseFrames only currently implements reuse of DataFrames.
  1153  	for i := 0; i < numNewDataFrames; i++ {
  1154  		df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
  1155  		for _, item := range dfSoFar {
  1156  			if df == item {
  1157  				t.Errorf("Expected Framer to return new DataFrames since SetNoReuseFrames not set.")
  1158  			}
  1159  		}
  1160  		dfSoFar[i] = df
  1161  	}
  1162  }
  1163  
  1164  func readAndVerifyDataFrame(data string, length byte, fr *Framer, buf *bytes.Buffer, t *testing.T) *DataFrame {
  1165  	var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
  1166  	fr.WriteData(streamID, true, []byte(data))
  1167  	wantEnc := "\x00\x00" + string(length) + "\x00\x01\x01\x02\x03\x04" + data
  1168  	if buf.String() != wantEnc {
  1169  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
  1170  	}
  1171  	f, err := fr.ReadFrame()
  1172  	if err != nil {
  1173  		t.Fatal(err)
  1174  	}
  1175  	df, ok := f.(*DataFrame)
  1176  	if !ok {
  1177  		t.Fatalf("got %T; want *DataFrame", f)
  1178  	}
  1179  	if !bytes.Equal(df.Data(), []byte(data)) {
  1180  		t.Errorf("got %q; want %q", df.Data(), []byte(data))
  1181  	}
  1182  	if f.Header().Flags&1 == 0 {
  1183  		t.Errorf("didn't see END_STREAM flag")
  1184  	}
  1185  	return df
  1186  }
  1187  
  1188  func encodeHeaderRaw(t *testing.T, pairs ...string) []byte {
  1189  	var he hpackEncoder
  1190  	return he.encodeHeaderRaw(t, pairs...)
  1191  }
  1192  
  1193  func TestSettingsDuplicates(t *testing.T) {
  1194  	tests := []struct {
  1195  		settings []Setting
  1196  		want     bool
  1197  	}{
  1198  		{nil, false},
  1199  		{[]Setting{{ID: 1}}, false},
  1200  		{[]Setting{{ID: 1}, {ID: 2}}, false},
  1201  		{[]Setting{{ID: 1}, {ID: 2}}, false},
  1202  		{[]Setting{{ID: 1}, {ID: 2}, {ID: 3}}, false},
  1203  		{[]Setting{{ID: 1}, {ID: 2}, {ID: 3}}, false},
  1204  		{[]Setting{{ID: 1}, {ID: 2}, {ID: 3}, {ID: 4}}, false},
  1205  
  1206  		{[]Setting{{ID: 1}, {ID: 2}, {ID: 3}, {ID: 2}}, true},
  1207  		{[]Setting{{ID: 4}, {ID: 2}, {ID: 3}, {ID: 4}}, true},
  1208  
  1209  		{[]Setting{
  1210  			{ID: 1}, {ID: 2}, {ID: 3}, {ID: 4},
  1211  			{ID: 5}, {ID: 6}, {ID: 7}, {ID: 8},
  1212  			{ID: 9}, {ID: 10}, {ID: 11}, {ID: 12},
  1213  		}, false},
  1214  
  1215  		{[]Setting{
  1216  			{ID: 1}, {ID: 2}, {ID: 3}, {ID: 4},
  1217  			{ID: 5}, {ID: 6}, {ID: 7}, {ID: 8},
  1218  			{ID: 9}, {ID: 10}, {ID: 11}, {ID: 11},
  1219  		}, true},
  1220  	}
  1221  	for i, tt := range tests {
  1222  		fr, _ := testFramer()
  1223  		fr.WriteSettings(tt.settings...)
  1224  		f, err := fr.ReadFrame()
  1225  		if err != nil {
  1226  			t.Fatalf("%d. ReadFrame: %v", i, err)
  1227  		}
  1228  		sf := f.(*SettingsFrame)
  1229  		got := sf.HasDuplicates()
  1230  		if got != tt.want {
  1231  			t.Errorf("%d. HasDuplicates = %v; want %v", i, got, tt.want)
  1232  		}
  1233  	}
  1234  
  1235  }